zoukankan      html  css  js  c++  java
  • GERALD07加强版:lct,主席树,边化点

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

    传送门

    lct这么神仙的东西一个题解都不写怎么行???

    神仙思路啊。

    其实不是很难但是的确不容易想到。

    我们考虑答案是什么。

    首先刚开始有n个点分别是联通块,然后你连了一些边使联通块减少了。

    怎么减少的呢?就是区间的边的生成树上边的数量。因为如果不是生成树上的边,那么一定与生成树上的边成环了而不会合并联通块。

    怎么判断边是不是区间内生成树上的边呢?判断依据就是它有没有和前面的边成环。

    那么我们先把边连起来,当连边时我们发现这两个点已经联通时,这条边就可以取代出现的最早的那条边。

    如果它取代的那条边不在区间之内,那么这条边就在生成树上。

    所以就来一棵LCT,边化点后维护最大编号就行,把每条边插入之前询问会被替代的边,存在数组lst里。

    那么对于每一组询问,问题就变成了问在数组lst下标[l,r]内lst值小于l的有几个。

    用主席树维护一下就好了。

    记住这种思路。

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 int c[400005][2],f[400005],w[400005],n,m,k,opt,fid[400005],lst[200005],q[400005];
     5 int x[200005],y[200005],ans,rt[200005],v[5000005],t[5000005][2],lz[400005],cnt;
     6 int find(int p){return fid[p]==p?p:fid[p]=find(fid[p]);}
     7 #define lc c[p][0]
     8 #define rc c[p][1]
     9 bool not_root(int p){return c[f[p]][0]==p||c[f[p]][1]==p;}
    10 void rev(int p){lc^=rc^=lc^=rc;lz[p]^=1;}
    11 void down(int p){if(lz[p])rev(lc),rev(rc),lz[p]=0;}
    12 void up(int p){w[p]=min(p>n?p:1234567890,min(w[lc],w[rc]));}
    13 void rotate(int p){
    14     int fa=f[p],gr=f[fa],dir=c[fa][1]==p,br=c[p][!dir];
    15     if(not_root(fa))c[gr][c[gr][1]==fa]=p; c[p][!dir]=fa; c[fa][dir]=br;
    16     f[p]=gr; f[fa]=p; f[br]=fa; up(fa);
    17 }
    18 void splay(int p){
    19     int res=p,top=0;q[++top]=p;
    20     while(not_root(res))q[++top]=res=f[res];
    21     while(top)down(q[top--]);
    22     while(not_root(p)){
    23         int fa=f[p],gr=f[fa];
    24         if(not_root(fa))rotate(c[fa][1]==p^c[gr][1]==fa?fa:p);
    25         rotate(p);
    26     }
    27     up(p);
    28 }
    29 void access(int p){for(int y=0;p;p=f[y=p])splay(p),rc=y,up(p);}
    30 void make_root(int p){access(p);splay(p);rev(p);}
    31 void split(int x,int y){make_root(x);access(y);splay(y);}
    32 void cut(int x,int y){split(x,y);f[x]=c[y][0]=0;up(y);}
    33 void link(int x,int y){make_root(x);f[x]=y;up(y);}
    34 void build(int &p,int cpy,int adx,int l=0,int r=m){
    35     if(!p)p=++cnt;
    36     if(l==r){v[p]=v[cpy]+1;return;}
    37     if(adx<=l+r>>1)build(t[p][0],t[cpy][0],adx,l,l+r>>1),t[p][1]=t[cpy][1];
    38     else build(t[p][1],t[cpy][1],adx,(l+r>>1)+1,r),t[p][0]=t[cpy][0];
    39     v[p]=v[t[p][0]]+v[t[p][1]];//printf("%d %d %d
    ",l,r,v[p]);
    40 }
    41 int ask(int p1,int p2,int l,int r,int cl=0,int cr=m){//printf("%d %d %d %d
    ",cl,cr,v[p2],v[p1]);
    42     if(!(v[p2]-v[p1]))return 0;
    43     if(l<=cl&&cr<=r)return v[p2]-v[p1];
    44     return (l<=cl+cr>>1?ask(t[p1][0],t[p2][0],l,r,cl,cl+cr>>1):0)+(r>cl+cr>>1?ask(t[p1][1],t[p2][1],l,r,(cl+cr>>1)+1,cr):0);
    45 }
    46 int main(){w[0]=1234567890;
    47     scanf("%d%d%d%d",&n,&m,&k,&opt);
    48     for(int i=1;i<=n;++i)fid[i]=i;
    49     for(int i=1;i<=m;++i){
    50         scanf("%d%d",&x[i],&y[i]);
    51         if(x[i]==y[i])lst[i]=i;
    52         else if(find(x[i])!=find(y[i]))fid[fid[x[i]]]=fid[y[i]],link(x[i],n+i),link(n+i,y[i]);
    53         else split(x[i],y[i]),lst[i]=w[y[i]]-n,cut(lst[i]+n,x[lst[i]]),cut(lst[i]+n,y[lst[i]]),
    54             link(x[i],n+i),link(y[i],n+i);
    55         build(rt[i],rt[i-1],lst[i]);//printf("%d
    ",lst[i]);
    56     }
    57     for(int i=1,l,r;i<=k;++i){
    58         scanf("%d%d",&l,&r);
    59         if(opt)l^=ans,r^=ans;
    60         ans=n-ask(rt[l-1],rt[r],0,l-1);
    61         printf("%d
    ",ans);
    62     }
    63 }
    View Code
  • 相关阅读:
    Zero-Copy&sendfile浅析
    Redis数据清除问题
    Redis官方文档》持久化
    GNU C 、ANSI C、标准C、标准c++区别和联系
    有关jQuery valid 验证多个同name属性的input的问题
    jQuery validator 增加多个模板
    archiver error. Connect internal only, until freed. 之解决办法
    链接ftp,把文件或图片上传到ftp指定的文件夹中
    java 数字金额转换中文金额
    java工具类 --千分位方法
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11566956.html
Copyright © 2011-2022 走看看