lct总结

Posted loadingkkk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lct总结相关的知识,希望对你有一定的参考价值。

lct=long code tree

推荐博客:https://www.cnblogs.com/flashhu/p/8324551.html,讲得很详细。

先放题解包,自己的理解会后续加上。

T1:Cave 洞穴勘测

板子题,lct的用途之一:维护联通性,相当与一个可以断边的并查集

T2:树的维护

用lct维护边权,考虑把边化为点,对边权的处理会有许多便利。也是对类似题提供一个思路。

回到这题,因为有取负数的操作,考虑再维护一个最小值,下传标记时交换最大值和最小值,再分别取负。

具体实现见代码

技术图片
  1 #include<bits/stdc++.h>
  2 #define N 20050
  3 #define cri const register int
  4 using namespace std;
  5 int n;
  6 struct node{int x,y,z,id;}ed[N];
  7 int w[N],w2[N],val[N],val2[N],ch[N][2],fa[N],t1[N],t2[N];
  8 
  9 inline void pr(int g)
 10 {
 11     printf("g:%d fa:%d lc:%d rc:%d val:%d val2:%d w:%d w2:%d t1:%d t2:%d
",g,fa[g],ch[g][0],ch[g][1],val[g],val2[g],w[g],w2[g],t1[g],t2[g]);
 12 }
 13 inline void bl(int g)
 14 {
 15     if(!g)return;//down(g);
 16     bl(ch[g][0]);
 17     pr(g);
 18     bl(ch[g][1]);
 19 }
 20 
 21 
 22 inline int Max(cri a,cri b){if(a>b)return a;return b;}
 23 inline int Min(cri a,cri b){if(a<b)return a;return b;}
 24 inline bool nroot(cri x){
 25     return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
 26 }
 27 inline bool Get(cri x){return ch[fa[x]][1]==x;}
 28 inline void push1(cri x){
 29     swap(ch[x][0],ch[x][1]);t1[x]^=1;
 30 }
 31 inline void push2(cri x){
 32     if(!x)return;
 33 //    printf("inp2:");pr(x);
 34     if(x>n)val[x]=-val[x],val2[x]=-val2[x];
 35     swap(w[x],w2[x]),w[x]=-w[x],w2[x]=-w2[x];
 36 //    printf("inp2:");pr(x);
 37     t2[x]^=1;
 38 }
 39 inline void upd(cri x){
 40     w[x]=Max(w[ch[x][0]],w[ch[x][1]]);
 41     w[x]=Max(w[x],val[x]);
 42     w2[x]=Min(w2[ch[x][0]],w2[ch[x][1]]);
 43     w2[x]=Min(w2[x],val2[x]);
 44 }
 45 inline void down(cri x){
 46     if(t1[x]){
 47         push1(ch[x][0]);push1(ch[x][1]);
 48         t1[x]=0;
 49     }
 50     if(t2[x]){
 51         push2(ch[x][0]);push2(ch[x][1]);
 52         t2[x]=0;
 53     }
 54 //    upd(x);
 55 }
 56 inline void rotate(int x){
 57     cri y=fa[x],z=fa[y],p=Get(x),ww=ch[x][p^1];
 58 //    cout<<"y::"<<y<<" "<<w[y]<<endl;
 59 //    cout<<"x::"<<x<<" "<<w[x]<<endl;
 60     if(ww)fa[ww]=y;ch[y][p]=ww;
 61     if(nroot(y))ch[z][Get(y)]=x;fa[x]=z;
 62     fa[y]=x;ch[x][p^1]=y;
 63 
 64     upd(y);upd(x);
 65 
 66 }
 67 inline void pushall(cri x){
 68     if(nroot(x))pushall(fa[x]);
 69     down(x);
 70 }
 71 inline void splay(cri x){
 72     pushall(x);
 73     while(nroot(x)){
 74         cri y=fa[x];
 75         if(nroot(y))Get(x)==Get(y)?rotate(y):rotate(x);
 76         rotate(x);
 77     }
 78     upd(x);
 79 }
 80 inline void access(int x){
 81     for(int y=0;x;x=fa[y=x])splay(x),ch[x][1]=y,upd(x);
 82     upd(x);
 83 }
 84 inline void findroot(int x){
 85     access(x);splay(x);
 86     while(ch[x][0])down(x),x=ch[x][0];
 87     splay(x);
 88 }
 89 inline void makeroot(cri x){access(x);splay(x);push1(x);upd(x);}
 90 inline void link(cri x,cri y){
 91     makeroot(x);fa[x]=y;upd(x);
 92 }
 93 
 94 inline void split(int x,int y){
 95     makeroot(x);makeroot(y);
 96 }
 97 
 98 int main()
 99 {
100 //    freopen("da.in","r",stdin);
101     scanf("%d",&n);int m=n;
102     memset(val,-0x3f,sizeof(val));
103     memset(w,-0x3f,sizeof(w));
104     memset(w2,0x3f,sizeof(w2));
105     memset(val2,0x3f,sizeof(val2));
106     for(int i=1;i<n;++i){
107         scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].z);
108         ed[i].id=++m;
109         val[m]=val2[m]=ed[i].z;
110         link(ed[i].x,m);
111         link(ed[i].y,m);
112         upd(m);
113     }
114 //    for(int i=1;i<=m;++i)bl(i);
115     string s;
116     int x,y;
117     int kkk=0;
118     while(1)
119     {
120 //        printf("kkk:%d
",++kkk);
121         cin>>s;
122         if(s[0]==D)return 0;
123         scanf("%d%d",&x,&y);
124         if(s[0]==C)
125         {
126             makeroot(ed[x].id);
127             val[ed[x].id]=y;
128             val2[ed[x].id]=y;
129             upd(ed[x].id);
130         }
131         else if(s[0]==N)
132         {
133             split(x,y);
134             push2(y);
135 //            bl(y);puts("yessssssssssssssssssssssssssss");
136 //            pr(0);
137         }
138         else
139         {
140             split(x,y);
141             printf("%d
",w[y]);
142 //            bl(y);
143         }
144     }
145 }
View Code

T3:tree

此题为对懒标记的考察。因为要用到加法标记和乘法标记,一开始我想开vector统计标记,然后就MLE了。真kx。其实仔细思考一下,发现,可以先下放乘法标记,再下放加法标记

加入新的加法标记时直接在原加法标记上累加。加入乘法标记时,当前点所有的加法标记都要乘加入的乘法标记,然后再将原乘法标记乘加入的乘法标记。

然后只维护一个加法标记和一个乘法标记即可,注意开unsigned

T4:水管局长加强版

lct维护边权,因为是图,删掉边后难以找到要加入的边,考虑时光倒流。先把所有能够加入的边加入lct,用lct维护一棵最小生成树。

在新加入边时先查询lct中对应两点是否连通,若联通则看路径上的最大边权和要加入边的边权的大小关系。

具体实现见代码

技术图片
  1 #include<bits/stdc++.h>
  2 #define N 1200000
  3 #define cri const register int
  4 using namespace std;
  5 int n,m,q;
  6 int fa[N],ch[N][2],w[N],val[N],t1[N];
  7 struct node{int x,y,z,pd;}ed[N],qq[100050];
  8 unordered_map<long long,int>h;
  9 inline void pr(int x){
 10     printf("x:%d f:%d l:%d r:%d v:%d w:%d t1:%d
",x,fa[x],ch[x][0],ch[x][1],val[x],w[x],t1[x]);
 11 }
 12 inline int Get(cri x){
 13     return ch[fa[x]][1]==x;
 14 }
 15 inline int nroot(cri x){
 16     return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
 17 }
 18 inline void upd(cri x){
 19     w[x]=max(w[ch[x][0]],w[ch[x][1]]);
 20     w[x]=max(w[x],val[x]);
 21 }
 22 inline void push1(cri x){
 23     swap(ch[x][0],ch[x][1]);t1[x]^=1;
 24 }
 25 inline void down(cri x){
 26     if(t1[x])push1(ch[x][0]),push1(ch[x][1]),t1[x]=0;
 27 }
 28 inline void rotate(cri x){
 29     cri y=fa[x],z=fa[y],p=Get(x),w=ch[x][p^1];
 30     if(w)fa[w]=y;ch[y][p]=w;
 31     if(nroot(y))ch[z][Get(y)]=x;fa[x]=z;
 32     fa[y]=x;ch[x][p^1]=y;
 33     upd(y);upd(x);
 34 }
 35 inline void pushall(cri x){
 36     if(nroot(x))pushall(fa[x]);down(x);
 37 }
 38 inline void splay(cri x){
 39     pushall(x);
 40     while(nroot(x)){
 41         cri y=fa[x];
 42         if(nroot(y))Get(y)==Get(x)?rotate(y):rotate(x);
 43         rotate(x);
 44     }
 45 }
 46 inline void access(int x){
 47     for(int y=0;x;x=fa[y=x])splay(x),ch[x][1]=y,upd(x);
 48 }
 49 inline void makeroot(cri x){
 50     access(x);splay(x);push1(x);
 51 }
 52 inline void split(cri x,cri y){
 53     makeroot(x);access(y);splay(y);
 54 }
 55 inline void link(cri x,cri y){
 56     makeroot(x);fa[x]=y;
 57 }
 58 inline void cut(cri x,cri y){
 59     split(x,y);ch[y][0]=fa[x]=0;upd(y);
 60 }
 61 inline int findroot(int x){
 62     while(ch[x][0])down(x),x=ch[x][0];
 63     splay(x);return x;
 64 }
 65 inline bool linked(cri x,cri y){
 66     split(x,y);return findroot(y)==x;
 67 }
 68 
 69 inline int getma(cri x,cri y){
 70     split(x,y);return w[y];
 71 }
 72 inline int find(int x){
 73     while(1){
 74         if(w[x]==val[x])return x;
 75         x=w[x]==w[ch[x][0]]?ch[x][0]:ch[x][1];
 76     }
 77 }
 78 
 79 inline void add(node e,int id){
 80 //    if(id==8){
 81 //        for(int i=1;i<=n+m;++i)pr(i);
 82 //        puts("noooooo");
 83 //    }
 84     if(!linked(e.x,e.y)){
 85     //    puts("nothere");
 86         val[id]=e.z;
 87         link(e.x,id);
 88         link(e.y,id);
 89         upd(id);
 90     }
 91     else{
 92         int t=getma(e.x,e.y);
 93         if(t>e.z){
 94     //        puts("yess");
 95             t=find(e.y);
 96 //            cout<<"t:"<<t<<endl;
 97             split(ed[t-n].x,ed[t-n].y);
 98             splay(t);
 99             fa[ch[t][0]]=fa[ch[t][1]]=0;
100             val[id]=e.z;
101             link(e.x,id);
102             link(e.y,id);
103             upd(id);
104         }
105     }
106 }
107 int main()
108 {
109 //    freopen("da.in","r",stdin);
110     scanf("%d%d%d",&n,&m,&q);
111     for(int i=1;i<=m;++i){
112         scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].z);
113         if(ed[i].x>ed[i].y)swap(ed[i].x,ed[i].y);
114         h[1ll*ed[i].x*n+ed[i].y]=i;
115     }
116     for(int i=1;i<=q;++i){
117         scanf("%d%d%d",&qq[i].pd,&qq[i].x,&qq[i].y);
118         if(qq[i].pd==2){
119             if(qq[i].x>qq[i].y)swap(qq[i].x,qq[i].y);
120             qq[i].z=h[1ll*qq[i].x*n+qq[i].y];
121             ed[qq[i].z].pd=1;
122         }
123     }
124 //    puts("ed");
125     for(int i=1;i<=m;++i)
126         if(!ed[i].pd)add(ed[i],i+n);
127 //    puts("ed2");
128     for(int i=q;i;--i){
129 //        cout<<i<<endl;
130 //        if(i==1||i==2){
131 //            for(int j=1;j<=n+m;++j)pr(j);
132 //            puts("yes");
133 //        }
134         if(qq[i].pd==1){
135             qq[i].z=getma(qq[i].x,qq[i].y);
136         }
137         else{
138 //            cout<<"i"<<i<<" "<<qq[i].z<<endl;
139             add(ed[qq[i].z],qq[i].z+n);
140         }
141     }
142 //    puts("ed3");
143     for(int i=1;i<=q;++i){
144         if(qq[i].pd==1){
145             printf("%d
",qq[i].z);
146         }
147     }
148     return 0;
149 }
View Code

T5:GERALD07加强版

一开始看见这题挺蒙的,用lct维护一段区间内的边。然后发现根本不可做。

考虑求连通块个数可以点数减去边数,但这只适用于森林,对于图根本不可行。

那么是不是删掉一些边把图转换为树就可以点数减边数了?

考虑从前往后加边,用lct维护连通性,新加入一个边时,查询原lct中两点是否联通,

若已经联通则找到路径上编号最小的边(记为pre)删掉,并加入主席树进行维护。

代表的含义就是:当前边与pre同时出现时,当前边不会作贡献

维护主席树,在每个点插入对应的pre,查询是直接在右端点处的主席树查询从左端点到右端点有多少个pre

即为当前区间被干掉了多少条边。

注:自环的pre为自己,自环不能加入lct

技术图片
  1 #include<bits/stdc++.h>
  2 #define N 400050
  3 #define lc ch[x][0]
  4 #define rc ch[x][1]
  5 using namespace std;
  6 int n,m,k;
  7 int fa[N],ch[N][2],w[N],val[N],t1[N];
  8 inline void pr(int x){
  9     printf("x:%d f:%d l:%d r:%d v:%d w:%d t:%d
",x,fa[x],lc,rc,val[x],w[x],t1[x]);
 10 }
 11 inline int Get(int x){
 12     return ch[fa[x]][1]==x;
 13 }
 14 inline int nroot(int x){
 15     return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
 16 }
 17 inline void push1(int x){
 18     swap(lc,rc);t1[x]^=1;
 19 }
 20 inline void down(int x){
 21     if(t1[x])push1(lc),push1(rc),t1[x]^=1;
 22 }
 23 inline void upd(int x){
 24     w[x]=min(w[lc],w[rc]);w[x]=min(w[x],val[x]);
 25 }
 26 inline void rotate(int x){
 27     int y=fa[x],z=fa[y],p=Get(x),w=ch[x][p^1];
 28     if(w)fa[w]=y;ch[y][p]=w;
 29     if(nroot(y))ch[z][Get(y)]=x;fa[x]=z;
 30     fa[y]=x;ch[x][p^1]=y;
 31     upd(y);upd(x);
 32 }
 33 void pushall(int x){
 34     if(nroot(x))pushall(fa[x]);down(x);
 35 }
 36 inline void splay(int x){
 37     pushall(x);
 38     while(nroot(x)){
 39         int y=fa[x];
 40         if(nroot(y))Get(x)==Get(y)?rotate(y):rotate(x);
 41         rotate(x);
 42     }
 43 }
 44 inline void access(int x){
 45     for(int y=0;x;x=fa[y=x])splay(x),rc=y,upd(x);
 46 }
 47 inline void makeroot(int x){
 48     access(x);splay(x);push1(x);
 49 }
 50 inline void split(int x,int y){
 51     makeroot(x);access(y);splay(y);
 52 }
 53 inline void link(int x,int y){
 54     makeroot(x);fa[x]=y;
 55 }
 56 inline void cut(int x,int y){
 57     split(x,y);ch[y][0]=fa[x]=0;upd(y);
 58 }
 59 inline int findroot(int x){
 60     while(lc)down(x),x=lc;splay(x);return x;
 61 }
 62 inline bool linked(int x,int y){
 63     split(x,y);return findroot(y)==x;
 64 }
 65 struct node{
 66     int x,y,pre;
 67 }ed[N];
 68 #undef lc
 69 #undef rc
 70 struct hjt{
 71     int rt[N],lc[N*20],rc[N*20],sum[N*20],tot;
 72     inline void upd(int g){
 73         sum[g]=sum[lc[g]]+sum[rc[g]];
 74     }
 75     inline void add(int &g,int f,int l,int r,int x){
 76         if(!g)g=++tot;
 77         sum[g]=sum[f]+1;
 78         if(l==r)return;
 79         const int m=l+r>>1;
 80         if(x<=m)rc[g]=rc[f],add(lc[g],lc[f],l,m,x);
 81         else lc[g]=lc[f],add(rc[g],rc[f],m+1,r,x);
 82         upd(g);
 83     //    printf("g:%d f:%d l:%d r:%d s:%d
",g,f,lc[g],rc[g],sum[g]);
 84     }
 85     inline int ask(int g,int l,int r,int x,int y){
 86         if(!g)return 0;
 87         if(l>=x&&r<=y)return sum[g];
 88         if(l>y||r<x)return 0;
 89         const int m=l+r>>1;
 90         return ask(lc[g],l,m,x,y)+ask(rc[g],m+1,r,x,y);
 91     }
 92 }k2;
 93 inline int add(int id,node e){
 94     if(!linked(e.x,e.y)){
 95         val[id]=id-n;
 96         link(id,e.x);
 97         link(id,e.y);
 98         return 0;
 99     }
100     else{
101         split(e.x,e.y);int ret=w[e.y];
102         int t=ret+n;
103         split(ed[ret].x,ed[ret].y);
104         splay(t);
105         fa[ch[t][0]]=fa[ch[t][1]]=0;
106         val[id]=id-n;
107         link(id,e.x);
108         link(id,e.y);
109         return ret;
110     }
111 }
112 int main(){
113 //    freopen("da.in","r",stdin);
114     //freopen("my.out","w",stdout);
115     memset(val,0x3f,sizeof(val));
116     memset(w,0x3f,sizeof(w));
117     int type;
118     scanf("%d%d%d%d",&n,&m,&k,&type);
119     for(int i=1;i<=m;++i){
120         scanf("%d%d",&ed[i].x,&ed[i].y);
121         if(ed[i].x==ed[i].y)ed[i].pre=i;
122         else ed[i].pre=add(i+n,ed[i]);
123 
124         if(ed[i].pre)k2.add(k2.rt[i],k2.rt[i-1],1,m,ed[i].pre);
125         else k2.rt[i]=k2.rt[i-1];
126     //    printf("pre[%d]=%d
",i,ed[i].pre);
127     }
128     for(int i=1,ans=0,x,y;i<=k;++i){
129         scanf("%d%d",&x,&y);
130         if(type)x^=ans,y^=ans;ans=n;
131         ans-=y-x+1-k2.ask(k2.rt[y],1,m,x,y);
132         printf("%d
",ans);
133     }
134     return 0;
135 }
View Code

以上是关于lct总结的主要内容,如果未能解决你的问题,请参考以下文章

LCT总结——应用篇(附题单)(LCT)

LCT入门总结

lct总结

lct总结

LCT好题总结

洛谷P4219 [BJOI2014]大融合(LCT,Splay)