zoukankan      html  css  js  c++  java
  • [BZOJ2959]长跑(LCT+并查集)

    用LCT支持:在线加边,单点修改,求一个两个点路径上的所有边BCC的点权和。

    用LCT维护边BCC的形态(即缩边双之后的树),2,3操作都是LCT基本操作,重点考虑加边操作。

    当这条边的两个端点属于同一BCC时显然没有任何影响。当两个端点不在同一个连通块里时直接在LCT上做link(bel[x],bel[y])即可。

    当两个端点在同一个连通块里但不在同一个BCC中时,相当于将(缩点后的)树上两个点之间的路径全部缩成一个点。

    由于过程中有频繁的点合并操作,所以再拿一个并查集记录每个BCC目前真正属于哪个BCC(即它被合并到哪个点去了),链合并的时候,先split(x,y)分离出这条链,再将链上所有点的fa[](并查集上的父亲)全部设为y,再将y左子树整个删去。在LCT操作中,我们所有的f[x](LCT上的父亲)全部变为find(f[x]),这样那些链上连出去的虚子树就能找到自己的新父亲(y)了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=150010;
     7 int n,m,op,x,y,v[N],f[N],fa1[N],fa2[N],c[N][2],w[N],sm[N],rev[N];
     8 
     9 int get1(int x){ return x==fa1[x] ? x : fa1[x]=get1(fa1[x]); }
    10 int get2(int x){ return x==fa2[x] ? x : fa2[x]=get2(fa2[x]); }
    11 void upd(int x){ sm[x]=sm[c[x][0]]+sm[c[x][1]]+w[x]; }
    12 void push(int x){ if (rev[x]) swap(c[x][0],c[x][1]),rev[c[x][0]]^=1,rev[c[x][1]]^=1,rev[x]=0; }
    13 bool isrt(int x){ return c[get1(f[x])][1]!=x && c[get1(f[x])][0]!=x; }
    14 void pd(int x){ if (!isrt(x)) pd(get1(f[x])); push(x); }
    15 
    16 void rot(int x){
    17     int y=get1(f[x]),z=get1(f[y]),w=(c[y][1]==x);
    18     if (!isrt(y)) c[z][c[z][1]==y]=x;
    19     f[x]=z; f[y]=x; f[c[x][w^1]]=y;
    20     c[y][w]=c[x][w^1]; c[x][w^1]=y; upd(y);
    21 }
    22 
    23 void splay(int x){
    24     for (pd(x); !isrt(x); rot(x)){
    25         int y=get1(f[x]),z=get1(f[y]);
    26         if (!isrt(y)) rot((c[y][0]==x)^(c[z][0]==y)?x:y);
    27     }
    28     upd(x);
    29 }
    30 
    31 void access(int x){ for (int y=0; x; y=x,x=get1(f[x])) splay(x),c[x][1]=y,upd(x); }
    32 void mkrt(int x){ access(x); splay(x); rev[x]^=1; }
    33 void link(int x,int y){ mkrt(x); f[x]=y; }
    34 void split(int x,int y){ mkrt(x); access(y); splay(y); }
    35 void cut(int x,int y){ split(x,y); c[y][0]=f[x]=0; upd(y); }
    36 
    37 void dfs(int x,int y){
    38     fa1[x]=y; push(x);
    39     if (c[x][0]) dfs(c[x][0],y);
    40     if (c[x][1]) dfs(c[x][1],y);
    41 }
    42 
    43 int main(){
    44     freopen("bzoj2959.in","r",stdin);
    45     freopen("bzoj2959.out","w",stdout);
    46     scanf("%d%d",&n,&m);
    47     rep(i,1,n) scanf("%d",&w[i]),sm[i]=v[i]=w[i],fa1[i]=fa2[i]=i;
    48     rep(i,1,m){
    49         scanf("%d%d%d",&op,&x,&y); int tx=get1(x),ty=op==2?0:get1(y);
    50         if (op==1){
    51             if (tx==ty) continue;
    52             if (get2(tx)!=get2(ty)) link(tx,ty),fa2[get2(tx)]=get2(ty);
    53                 else split(tx,ty),w[ty]=sm[ty],dfs(ty,ty),c[ty][0]=0;
    54         }
    55         if (op==2) splay(tx),w[tx]+=y-v[x],sm[tx]+=y-v[x],v[x]=y;
    56         if (op==3){
    57             if (get2(tx)!=get2(ty)) puts("-1");
    58                 else split(tx,ty),printf("%d
    ",sm[ty]);
    59         }
    60     }
    61     return 0;
    62 }
  • 相关阅读:
    extern “C”的作用详解
    const和typedef的常见用法详解
    虚函数、纯虚函数、虚函数与析构函数
    C++中四种类型转换方式
    面经中高频知识点归纳(一)
    leetcode Database4
    32位机和64位机下面各类型sizeof的大小
    Spring框架针对dao层的jdbcTemplate操作crud之query查询数据操作
    字符串变量的定义与引用
    使用字符数组及相关函数,求3个国家名中字母顺序排在最前面的国家。
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10641386.html
Copyright © 2011-2022 走看看