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 }
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 }
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 }
以上是关于lct总结的主要内容,如果未能解决你的问题,请参考以下文章