• BZOJ 3514 GERALD07加强版 (LCT+主席树)


    题目大意:给定n个点m条边无向图,每次询问求当图中有编号为[L,R]的边时,整个图的联通块个数,强制在线

    神题!(发现好久以前的题解没有写完诶)

    我们要求图中联通块的个数,似乎不可搞啊。

    联通块个数=n-树边条数!

    考虑每条边的贡献,我们按编号从小到大暴力枚举每一条边。

    考虑用$LCT$维护森林。

    设新加入的这条边编号为$e$,连接了$x,y$两个点

    如果$x,y$原来不连通,说明加入$e$会让图中多一条树边。边e对$Lin [1,e],Rgeq e$的图$[L,R]$产生一点贡献

    如果$x,y$原来就联通,说明加入$e$会产生环,并不会影响联通块个数。我们找出$e$所在环里编号最小的边$x$

    当$Lleq x$时,删掉边$x$,图$[L,R]$的树边个数不变。

    当$L>x$时,删掉边$x$,会让图$[L,R]$少一条树边。那么边$x$会对$Lin[x+1,e],Rgeq e$的的图$[L,R]$产生一点贡献

    如何处理询问?我们可以用主席树,主席树不同的根作为右端点,线段树维护对左端点的贡献。每次查询,主席树相减,然后单点查询

    如何维护贡献?主席树上打差分实现区间修改

    如何维护编号最小的边?把边转化成点扔到$LCT$里就行啦

      1 #include <queue>
      2 #include <vector>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 #define N1 401000
      7 #define M1 201000
      8 #define S1 (N1<<1)
      9 #define T1 (N1<<2)
     10 #define ll long long
     11 #define uint unsigned int
     12 #define rint register int 
     13 #define ull unsigned long long
     14 #define dd double
     15 #define il inline 
     16 #define inf 1000000000
     17 using namespace std;
     18  
     19 int gint()
     20 {
     21     int ret=0,fh=1;char c=getchar();
     22     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     23     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     24     return ret*fh;
     25 }
     26 int n,m,T,type;
     27 struct Edge{
     28 int x[M1],y[M1],cte;
     29 void ae(int u,int v)
     30 {cte++;x[cte]=u,y[cte]=v;}
     31 }E;
     32 struct SEG{
     33 int ls[N1*40],rs[N1*40],sum[N1*40],root[N1],tot;
     34 void pushup(int rt){sum[rt]=sum[ls[rt]]+sum[rs[rt]];}
     35 void build(int l,int r,int &rt)
     36 {   
     37     int mid=(l+r)>>1; rt=++tot;
     38     if(l==r) return;
     39     build(l,mid,ls[rt]);
     40     build(mid+1,r,rs[rt]);
     41 }
     42 void update(int x,int l,int r,int r1,int &r2,int w)
     43 {
     44     if((!r2)||(r1==r2)){r2=++tot,sum[r2]=sum[r1],ls[r2]=ls[r1],rs[r2]=rs[r1];}
     45     if(l==r) {sum[r2]+=w; return;} int mid=(l+r)>>1;
     46     if(x<=mid) update(x,l,mid,ls[r1],ls[r2],w);
     47     else update(x,mid+1,r,rs[r1],rs[r2],w);
     48     pushup(r2);
     49 }
     50 int query(int L,int R,int l,int r,int rt)
     51 {
     52     if(!rt||L>R) return 0;
     53     if(L<=l&&r<=R) return sum[rt];
     54     int mid=(l+r)>>1,ans=0;
     55     if(L<=mid) ans+=query(L,R,l,mid,ls[rt]);
     56     if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]);
     57     return ans; 
     58 }
     59 }s;
     60 namespace lct{
     61 int ch[N1][2],fa[N1],mi[N1],id[N1],rev[N1],tot;
     62 int idf(int x){return ch[fa[x]][0]==x?0:1;}
     63 int isroot(int x){return (ch[fa[x]][0]==x||ch[fa[x]][1]==x)?0:1;}
     64 void pushup(int x){mi[x]=min(x,min(mi[ch[x][0]],mi[ch[x][1]]));}
     65 void revers(int x){swap(ch[x][0],ch[x][1]),rev[x]^=1;}
     66 void pushdown(int x){if(rev[x]){revers(ch[x][0]),revers(ch[x][1]),rev[x]^=1;}}
     67 void rot(int x)
     68 {
     69     int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
     70     if(!isroot(y)) ch[ff][py]=x; fa[x]=ff;
     71     fa[ch[x][px^1]]=y,ch[y][px]=ch[x][px^1];
     72     ch[x][px^1]=y,fa[y]=x;
     73     pushup(y),pushup(x);
     74 }
     75 int stk[N1],tp;
     76 void splay(int x)
     77 {
     78     int y=x; stk[++tp]=x;
     79     while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];}
     80     while(tp){pushdown(stk[tp--]);}
     81     while(!isroot(x))
     82     {
     83         y=fa[x];
     84         if(isroot(y)) rot(x);
     85         else if(idf(y)==idf(x)) rot(y),rot(x);
     86         else rot(x),rot(x);
     87     }
     88 }
     89 void access(int x){for(int y=0;x;y=x,x=fa[x]) splay(x),ch[x][1]=y,pushup(x);}
     90 void mkroot(int x){access(x),splay(x),revers(x);}
     91 void split(int x,int y){mkroot(x),access(y),splay(y);}
     92 int fdroot(int x){access(x),splay(x);while(ch[x][0])pushdown(ch[x][0]),x=ch[x][0];return x;}
     93 void cut(int x,int y){split(x,y);fa[x]=ch[y][0]=0,pushup(y);}
     94 void link(int x,int y){split(x,y);fa[x]=y;}
     95 //int isconn(int x,int y){split(x,y);if(!ch[x][1]&&fa[x]=y&&ch[y][0]==x) return 1;}
     96 void solve(int x,int y,int e)
     97 {
     98     split(x+m,y+m);
     99     if(x==y){
    100         int r1=s.root[e-1],r2=s.root[e]=++s.tot;
    101         s.sum[r2]=s.sum[r1],s.ls[r2]=s.ls[r1],s.rs[r2]=s.rs[r1];
    102     }else if(fdroot(y+m)!=x+m){
    103         s.update(1,1,m,s.root[e-1],s.root[e],1);
    104         if(e<m) s.update(e+1,1,m,s.root[e-1],s.root[e],-1);
    105     }else{
    106         int id=mi[y+m],xx=E.x[id],yy=E.y[id];
    107         cut(id,xx+m); cut(id,yy+m); 
    108         s.update(id+1,1,m,s.root[e-1],s.root[e],1);
    109         if(e<m) s.update(e+1,1,m,s.root[e-1],s.root[e],-1);
    110     }
    111     link(e,x+m),link(e,y+m);
    112 }
    113 };
    114 int tot;
    115  
    116 int main()
    117 {
    118     int i,j,x,y,Q,sx,sy,ans=0; tot=n+m;
    119     scanf("%d%d%d%d",&n,&m,&Q,&type);
    120     for(j=1;j<=m;j++) x=gint(), y=gint(), E.ae(x,y);
    121     s.build(1,m,s.root[0]);
    122     for(lct::mi[0]=inf,i=1;i<=n+m;i++) lct::mi[i]=i;
    123     for(j=1;j<=m;j++)
    124     {
    125         x=E.x[j]; y=E.y[j];
    126         lct::solve(x,y,j);
    127     }
    128     for(j=1;j<=Q;j++)
    129     {
    130         x=gint(), y=gint(); 
    131         if(type) x^=ans,y^=ans;
    132         sx=s.query(1,x,1,m,s.root[x-1]);
    133         sy=s.query(1,x,1,m,s.root[y]);
    134         ans=n-(sy-sx);
    135         printf("%d
    ",ans);
    136     }
    137     return 0;
    138 }
    139 
  • 相关阅读:
    浏览器的reflow和repaint
    javascript正则表达式中参数g的作用
    InkCanvas 自由虚线笔画
    WPF 圆轮菜单的实现
    WPF实现化学式上下标
    install and use zookeeper C client API
    install and use boost::thread
    explicit instantiations in template class/function
    The science of programming
    how does vector work?
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10165703.html
Copyright © 2020-2023  润新知