码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ3514】Codechef MARCH14 GERALD07加强版

时间:2017-12-28 23:34:58      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:output   100%   clu   etc   maker   sam   return   div   post   

---题目戳这

Description

N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

Input

第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

Output

K行每行一个整数代表该组询问的联通块个数。

Sample Input

3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2

Sample Output

2
1
3
1

HINT

对于100%的数据,1≤N、M、K≤200,000。

题解

我们不妨先依次加边,每加入一条边\(i\),就把与它形成的环上的时间最早的边\(j\)删掉,同时设ntr[i]=j,没有删边ntr[i]=0。这个可以用\(LCT\)做。特殊的,对于自环,我们有ntr[i]=i。
那么我们可以发现[l,r]的联通块个数就是n-[l,r]中ntr<l的个数。
很显然是对的,因为ntrl的边与之前的边形成了环,这条边显然是不能算进去的。
后面的查询可以用主席树维护。

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 400005;
int n,m,q,type,fa[N],ls[N],rs[N],rev[N],val[N],mn[N],Stack[N],top,u[N],v[N],ntr[N],rt[N],tot,ans;
struct president_tree{int ls,rs,num;}t[N*30];
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
void pushup(int x)
{
    mn[x]=x;
    if (ls[x]&&val[mn[ls[x]]]<val[mn[x]]) mn[x]=mn[ls[x]];
    if (rs[x]&&val[mn[rs[x]]]<val[mn[x]]) mn[x]=mn[rs[x]];
}
bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
void pushdown(int x){if (!rev[x]) return;swap(ls[x],rs[x]);rev[ls[x]]^=1;rev[rs[x]]^=1;rev[x]=0;}
void R_rotate(int x)
{
    int y=fa[x],z=fa[y];
    ls[y]=rs[x];
    if (rs[x]) fa[rs[x]]=y;
    fa[x]=z;
    if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
    rs[x]=y;fa[y]=x;
    pushup(y);
}
void L_rotate(int x)
{
    int y=fa[x],z=fa[y];
    rs[y]=ls[x];
    if (ls[x]) fa[ls[x]]=y;
    fa[x]=z;
    if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
    ls[x]=y;fa[y]=x;
    pushup(y);
}
void splay(int x)
{
    Stack[++top]=x;
    for (int i=x;!isroot(i);i=fa[i])
        Stack[++top]=fa[i];
    while (top) pushdown(Stack[top--]);
    while (!isroot(x))
    {
        int y=fa[x],z=fa[y];
        if (isroot(y))
            if (x==ls[y]) R_rotate(x);
            else L_rotate(x);
        else
            if (y==ls[z])
                if (x==ls[y]) R_rotate(y),R_rotate(x);
                else L_rotate(x),R_rotate(x);
            else
                if (x==ls[y]) R_rotate(x),L_rotate(x);
                else L_rotate(y),L_rotate(x);
    }
    pushup(x);
}
void access(int x){for (int y=0;x;y=x,x=fa[x]) splay(x),rs[x]=y,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=1;}
int findroot(int x){access(x);splay(x);while (ls[x]) x=ls[x];return x;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);fa[x]=ls[y]=0;}
void link(int x,int y){makeroot(x);fa[x]=y;}

void build(int &now,int l,int r)
{
    now=++tot;
    if (l==r) return;
    int mid=l+r>>1;
    build(t[now].ls,l,mid);
    build(t[now].rs,mid+1,r);
}
void update(int &now,int l,int r,int pos)
{
    t[++tot]=t[now];
    t[now=tot].num++;
    if (l==r) return;
    int mid=l+r>>1;
    if (pos<=mid) update(t[now].ls,l,mid,pos);
    else update(t[now].rs,mid+1,r,pos);
}
int Query(int A,int B,int l,int r,int ql,int qr)
{
    if (l>=ql&&r<=qr) return t[A].num-t[B].num;
    int mid=l+r>>1,s=0;
    if (ql<=mid) s+=Query(t[A].ls,t[B].ls,l,mid,ql,qr);
    if (qr>mid) s+=Query(t[A].rs,t[B].rs,mid+1,r,ql,qr);
    return s;
}
int main()
{
    n=gi();m=gi();q=gi();type=gi();
    for (int i=1;i<=n;i++) val[i]=1e9;
    for (int i=1;i<=m;i++)
    {
        u[i]=gi();v[i]=gi();
        if (u[i]==v[i]) {ntr[i]=i;continue;}
        if (findroot(u[i])^findroot(v[i]))
        {
            val[n+i]=i;
            link(u[i],n+i);link(v[i],n+i);
            //printf("link %d %d through edge %d\n",u[i],v[i],i);
        }
        else
        {
            split(u[i],v[i]);ntr[i]=mn[v[i]]-n;
            cut(u[ntr[i]],n+ntr[i]);cut(v[ntr[i]],n+ntr[i]);
            val[n+i]=i;
            link(u[i],n+i);link(v[i],n+i);
            //printf("cut edge %d between %d and %d in order to link edge %d \n",kan[i],u[kan[i]],v[kan[i]],i);
        }
    }
    build(rt[0],0,m);
    for (int i=1;i<=m;i++)
    {
        rt[i]=rt[i-1];
        update(rt[i],0,m,ntr[i]);
    }
    while (q--)
    {
        int l=gi(),r=gi();
        if (type) l^=ans,r^=ans;
        ans=n-Query(rt[r],rt[l-1],0,m,0,l-1);
        printf("%d\n",ans);
    }
    return 0;
}

【BZOJ3514】Codechef MARCH14 GERALD07加强版

标签:output   100%   clu   etc   maker   sam   return   div   post   

原文地址:https://www.cnblogs.com/zhoushuyu/p/8137927.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!