Ztxz16学图论

来源:互联网 发布:unity3d 汽车模型 编辑:程序博客网 时间:2024/05/29 18:55

题目大意

给定一张图,每次询问编号在[l,r]的边连上后会形成多少联通块。

离线做法

我们考虑莫队。
考虑左端点所在的每一块,左端点到块末最多根号的距离,右端点是单调的。并查集容易添加,因此只保留块末到右端点的联通情况,每次暴力加上块末到左端点部分。

在线做法

把加入1~i条边,每条边权值设置为编号,所形成的最大生成树叫第i个版本。
[l,r]的答案=第r个版本中联通块数量+第r个版本中[1,l-1]存在树中的数量
依次加上每条边,用LCT维护得到每个版本,然后得到其联通块数量。可持久化线段树来保存每个版本中边的出现情况。

#include<cstdio>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=200000+10,maxtot=8000000+10;int father[maxn*2],key[maxn*2],num[maxn*2],tree[maxn*2][2],pp[maxn*2];bool bz[maxn*2];int ans[maxn],root[maxn],left[maxtot],right[maxtot],sum[maxtot],fa[maxn],edge[maxn][2],sta[maxn*2];int i,j,k,l,r,t,n,m,q,tot,top,cnt,now;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9'){        if (ch=='-') f=-1;        ch=getchar();    }    while (ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x*f;}int getfa(int x){    return fa[x]?fa[x]=getfa(fa[x]):x;}int pd(int x){    return tree[father[x]][1]==x;}void update(int x){    num[x]=x;    if (tree[x][0])        if (key[num[tree[x][0]]]<key[num[x]]) num[x]=num[tree[x][0]];    if (tree[x][1])        if (key[num[tree[x][1]]]<key[num[x]]) num[x]=num[tree[x][1]];}void rotate(int x){    int y=father[x],z=pd(x);    father[x]=father[y];    if (father[y]) tree[father[y]][pd(y)]=x;    tree[y][z]=tree[x][1-z];    if (tree[x][1-z]) father[tree[x][1-z]]=y;    tree[x][1-z]=y;    father[y]=x;    update(y);    update(x);    if (pp[y]){        pp[x]=pp[y];        pp[y]=0;    }}void clear(int x){    if (bz[x]){        bz[tree[x][0]]^=1;        bz[tree[x][1]]^=1;        swap(tree[x][0],tree[x][1]);        bz[x]=0;    }}void remove(int x,int y){    cnt=0;    while (x!=y){        sta[++cnt]=x;        x=father[x];    }    while (cnt){        clear(sta[cnt]);        cnt--;    }}void splay(int x,int y){    remove(x,y);    while (father[x]!=y){        if (father[father[x]]!=y)            if (pd(x)==pd(father[x])) rotate(father[x]);else rotate(x);        rotate(x);    }}void access(int x){    int y;    splay(x,0);    if (tree[x][1]){        pp[tree[x][1]]=x;        father[tree[x][1]]=0;        tree[x][1]=0;        update(x);    }    while (x){        splay(x,0);        y=pp[x];        if (!y) break;        splay(y,0);        if (tree[y][1]){            pp[tree[y][1]]=y;            father[tree[y][1]]=0;        }        tree[y][1]=x;        pp[x]=0;        father[x]=y;        update(y);        x=y;    }}void makeroot(int x){    access(x);    splay(x,0);    bz[x]^=1;}int newnode(int x){    sum[++top]=sum[x];    left[top]=left[x];    right[top]=right[x];    return top;}void change(int &p,int l,int r,int a,int b){    p=newnode(p);    sum[p]+=b;    if (l==r) return;    int mid=(l+r)/2;    if (a<=mid) change(left[p],l,mid,a,b);else change(right[p],mid+1,r,a,b);}int query(int p,int l,int r,int a,int b){    if (a>b) return 0;    if (l==a&&r==b) return sum[p];    int mid=(l+r)/2;    if (b<=mid) return query(left[p],l,mid,a,b);    else if (a>mid) return query(right[p],mid+1,r,a,b);    else return query(left[p],l,mid,a,mid)+query(right[p],mid+1,r,mid+1,b);}void write(int x){    if (!x){        putchar('0');        putchar('\n');        return;    }    cnt=0;    while (x){        sta[++cnt]=x%10;        x/=10;    }    while (cnt){        putchar(sta[cnt]+'0');        cnt--;    }    putchar('\n');}int main(){    n=read();m=read();q=read();    tot=now=n;    fo(i,1,n) key[i]=m+1,num[i]=i;    fo(i,1,m){        j=read();k=read();        edge[i][0]=j;edge[i][1]=k;        root[i]=root[i-1];        tot++;        key[tot]=i;        num[tot]=tot;        if (j==k){            ans[i]=ans[i-1];            continue;        }        if (getfa(j)!=getfa(k)){            fa[getfa(k)]=getfa(j);            now--;            makeroot(k);            splay(k,0);            pp[k]=tot;            pp[tot]=j;            change(root[i],1,m,i,1);        }        else{            makeroot(j);            access(k);            splay(k,0);            l=num[k];            change(root[i],1,m,l-n,-1);            makeroot(l);            access(l);            splay(edge[l-n][0],0);            pp[edge[l-n][0]]=0;            splay(edge[l-n][1],0);            pp[edge[l-n][1]]=0;            makeroot(k);            splay(k,0);            pp[k]=tot;            pp[tot]=j;            change(root[i],1,m,i,1);        }        ans[i]=now;    }    while (q--){        l=read();r=read();        now=ans[r];        now+=query(root[r],1,m,1,l-1);        write(now);    }}
0 0