[关闭]
@exut 2024-11-14T02:46:57.000000Z 字数 5271 阅读 116

LCT的114514种处理寄巧

DS


本文针对的是会板子,稍微对LCT有一点点理解但是不会各种典型处理的人,比如我自己(bushi)

作者学到哪就写到哪,如果停止更新说明作者┏┛墓┗┓...(((m-__-)m

边权怎么办

众所周知的是树剖使用的是把边权放在深度较深的点上,查询时挖掉LCA的方式来实现边权转点权

但是,令人遗憾的是,LCT的动态结构不太支持这么搞

一种常见的处理方式(可能有更为厉害的处理方式,但是我并不会)

假如两个点在原树存在一条边,那么我们在他们俩之间建立一个点储存边的信息然后向两边连边

我们可以令第 条边的边点编号为 ,然后pushup和pushdown会有点难写

例子:P1505 [国家集训队] 旅游

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=4e5+5;
  4. const int inf=1e9;
  5. int val[N];
  6. int n,m;
  7. struct LCT{
  8. int fa[N],ch[N][2],rev[N],tag[N];
  9. int sum[N],mx[N],mi[N];
  10. bool isd(int x){return ch[fa[x]][2]==x;}
  11. bool isroot(int x){return (ch[fa[x]][0]!=x and ch[fa[x]][3]!=x);}
  12. void pushup(int x){
  13. if(x>n) sum[x]=mx[x]=mi[x]=val[x];
  14. else sum[x]=0,mx[x]=-inf,mi[x]=inf;
  15. sum[x]+=sum[ch[x][0]]+sum[ch[x][4]];
  16. if(ch[x][0]){
  17. mx[x]=max(mx[x],mx[ch[x][0]]);
  18. mi[x]=min(mi[x],mi[ch[x][0]]);
  19. }
  20. if(ch[x][5]){
  21. mx[x]=max(mx[x],mx[ch[x][6]]);
  22. mi[x]=min(mi[x],mi[ch[x][7]]);
  23. }
  24. }
  25. void pushdown(int x){
  26. if(rev[x]){
  27. rev[x]=0;
  28. swap(ch[x][0],ch[x][8]);
  29. rev[ch[x][0]]^=1;
  30. rev[ch[x][9]]^=1;
  31. }
  32. if(tag[x]){
  33. tag[x]=0;
  34. swap(mx[ch[x][0]],mi[ch[x][0]]);
  35. val[ch[x][0]]=-val[ch[x][0]];
  36. mx[ch[x][0]]=-mx[ch[x][0]];
  37. mi[ch[x][0]]=-mi[ch[x][0]];
  38. sum[ch[x][0]]=-sum[ch[x][0]];
  39. tag[ch[x][0]]^=1;
  40. swap(mx[ch[x][10]],mi[ch[x][11]]);
  41. val[ch[x][12]]=-val[ch[x][13]];
  42. mx[ch[x][14]]=-mx[ch[x][15]];
  43. mi[ch[x][16]]=-mi[ch[x][17]];
  44. sum[ch[x][18]]=-sum[ch[x][19]];
  45. tag[ch[x][20]]^=1;
  46. }
  47. }
  48. void rotate(int x){
  49. int y=fa[x],z=fa[y];
  50. int k=isd(x);
  51. if(!isroot(y)) ch[z][isd(y)]=x;
  52. fa[x]=z;
  53. ch[y][k]=ch[x][k^1];
  54. fa[ch[x][k^1]]=y;
  55. fa[y]=x;
  56. ch[x][k^1]=y;
  57. pushup(y),pushup(x);
  58. }
  59. stack<int,vector<int> > stk;
  60. void splay(int x){
  61. stk.push(x);
  62. for(int i=x;!isroot(i);i=fa[i]) stk.push(fa[i]);
  63. while(!stk.empty()) pushdown(stk.top()),stk.pop();
  64. while(!isroot(x)){
  65. int y=fa[x];
  66. if(!isroot(y)) (isd(x)==isd(y))?rotate(y):rotate(x);
  67. rotate(x);
  68. }
  69. }
  70. void access(int x){
  71. for(int t=0;x;t=x,x=fa[x])
  72. splay(x),ch[x][21]=t,pushup(x);
  73. }
  74. void makeroot(int x){
  75. access(x);
  76. splay(x);
  77. rev[x]^=1;
  78. }
  79. int findroot(int x){
  80. access(x);
  81. splay(x);
  82. while(ch[x][0]) x=ch[x][0];
  83. splay(x);
  84. return x;
  85. }
  86. void split(int x,int y){
  87. makeroot(x);
  88. access(y);
  89. splay(y);
  90. }
  91. void link(int x,int y){
  92. makeroot(x);
  93. if(findroot(y)!=x) fa[x]=y;
  94. }
  95. }lct;
  96. int main(){
  97. ios::sync_with_stdio(0);
  98. cin.tie(0),cout.tie(0);
  99. cin>>n;
  100. for(int i=1;i<n;i++){
  101. int u,v;
  102. cin>>u>>v;
  103. u++,v++;
  104. cin>>val[i+n];
  105. lct.link(u,i+n);
  106. lct.link(v,i+n);
  107. }
  108. cin>>m;
  109. while(m--){
  110. string opt;
  111. int x,y;
  112. cin>>opt>>x>>y;
  113. if(opt!="C") x++,y++;
  114. if(opt=="C"){
  115. lct.splay(x+n);
  116. val[x+n]=y;
  117. lct.pushup(x+n);
  118. }else if(opt=="N"){
  119. lct.split(x,y);
  120. lct.tag[y]^=1;
  121. }else if(opt=="SUM"){
  122. lct.split(x,y);
  123. cout<<lct.sum[y]<<"\n";
  124. }else if(opt=="MAX"){
  125. lct.split(x,y);
  126. cout<<lct.mx[y]<<"\n";
  127. }else if(opt=="MIN"){
  128. lct.split(x,y);
  129. cout<<lct.mi[y]<<"\n";
  130. }
  131. }
  132. }

维护生成树

以维护MST为例

P4172 [WC2006] 水管局长

一个典型的转化是瓶颈路最小就是最小生成树上链最大值

然后这道题的题意就转化成了LCT上维护MST

首先把删边逆序转化成加边,那么考虑在当前最小生成树的基础上加一条边的变化:多了一个环

如果加进来的边比当前环的最大值还要大,这个边毫无意义不需要加入

否则删掉最大边,并link上当前边即可

实现有点困难,细节有点多

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=2e5+5;
  4. const int inf=1e9;
  5. struct edge{
  6. int u,v,w;
  7. };
  8. vector<edge> e;
  9. struct que{
  10. int u,v;
  11. };
  12. que ctt[N];
  13. que Q[N];
  14. int n,m;
  15. int fa[N],ch[N][2],val[N],mx[N],mpos[N],rev[N];
  16. bool isd(int x){
  17. return ch[fa[x]][1]==x;
  18. }
  19. bool isroot(int x){
  20. return ch[fa[x]][0]!=x and ch[fa[x]][1]!=x;
  21. }
  22. void pushup(int x){
  23. if(x>n) mx[x]=val[x],mpos[x]=x;
  24. else mx[x]=-inf,mpos[x]=-1;
  25. if(ch[x][0]){
  26. if(mpos[ch[x][0]]!=-1 and (mpos[x]==-1 or mx[ch[x][0]]>mx[x])){
  27. mpos[x]=mpos[ch[x][0]];
  28. mx[x]=mx[ch[x][0]];
  29. }
  30. }
  31. if(ch[x][1]){
  32. if(mpos[ch[x][1]]!=-1 and (mpos[x]==-1 or mx[ch[x][1]]>mx[x])){
  33. mpos[x]=mpos[ch[x][1]];
  34. mx[x]=mx[ch[x][1]];
  35. }
  36. }
  37. }
  38. void pushdown(int x){
  39. if(rev[x]){
  40. rev[x]=0;
  41. swap(ch[x][0],ch[x][1]);
  42. if(ch[x][0]) rev[ch[x][0]]^=1;
  43. if(ch[x][1]) rev[ch[x][1]]^=1;
  44. }
  45. }
  46. void rotate(int x){
  47. int y=fa[x],z=fa[y];
  48. int k=isd(x);
  49. fa[ch[x][k^1]]=y;
  50. ch[y][k]=ch[x][k^1];
  51. if(!isroot(y)) ch[z][isd(y)]=x;
  52. fa[x]=z;
  53. fa[y]=x;
  54. ch[x][k^1]=y;
  55. pushup(y),pushup(x);
  56. }
  57. stack<int,vector<int> > stk;
  58. void splay(int x){
  59. stk.push(x);
  60. for(int i=x;!isroot(i);i=fa[i]) stk.push(fa[i]);
  61. while(!stk.empty()) pushdown(stk.top()),stk.pop();
  62. while(!isroot(x)){
  63. int y=fa[x];
  64. if(!isroot(y)) (isd(x)==isd(y))?rotate(y):rotate(x);
  65. rotate(x);
  66. }
  67. }
  68. void access(int x){
  69. for(int t=0;x;t=x,x=fa[x]){
  70. splay(x),ch[x][1]=t,pushup(x);
  71. }
  72. }
  73. void makeroot(int x){
  74. access(x);
  75. splay(x);
  76. rev[x]^=1;
  77. }
  78. int findroot(int x){
  79. access(x);
  80. splay(x);
  81. while(ch[x][0]) x=ch[x][0];
  82. splay(x);
  83. return x;
  84. }
  85. void split(int x,int y){
  86. makeroot(x);
  87. access(y);
  88. splay(y);
  89. }
  90. void link(int x,int y){
  91. makeroot(x);
  92. if(findroot(y)!=x) fa[x]=y;
  93. }
  94. void cut(int x,int y){
  95. makeroot(x);
  96. if(findroot(y)==x and fa[y]==x and !ch[y][0])
  97. fa[y]=ch[x][1]=0,pushup(x);
  98. }
  99. int q;
  100. int f[1005][1005];
  101. edge ct[N];
  102. bool cmp(edge x,edge y){
  103. return x.w<y.w;
  104. }
  105. int ufs[N];
  106. int find(int x){
  107. return x==ufs[x]?x:ufs[x]=find(ufs[x]);
  108. }
  109. int idx;
  110. int main(){
  111. ios::sync_with_stdio(0);
  112. cin.tie(0),cout.tie(0);
  113. cin>>n>>m>>q;
  114. for(int i=1;i<=m;i++){
  115. int u,v,w;
  116. cin>>u>>v>>w;
  117. f[u][v]=f[v][u]=w;
  118. // cin>>e[i].u>>e[i].v>>e[i].w;
  119. }
  120. for(int i=1;i<=q;i++){
  121. int k,x,y;
  122. cin>>k>>x>>y;
  123. if(k==1){
  124. Q[i]={x,y};
  125. }else{
  126. ct[i]={x,y,f[x][y]};
  127. f[x][y]=0;
  128. f[y][x]=0;
  129. }
  130. }
  131. for(int i=1;i<=n;i++){
  132. for(int j=i+1;j<=n;j++){
  133. if(f[i][j]) e.push_back({i,j,f[i][j]});
  134. }
  135. }
  136. idx=n;
  137. sort(e.begin(),e.end(),cmp);
  138. for(int i=1;i<=n;i++){
  139. ufs[i]=i;
  140. }
  141. for(auto L:e) {
  142. int u=L.u,v=L.v,w=L.w;
  143. if(find(u)==find(v)) continue;
  144. ufs[find(u)]=find(v);
  145. idx++;
  146. val[idx]=w;
  147. ctt[idx]={u,v};
  148. link(u,idx);
  149. link(v,idx);
  150. }
  151. stack<int,vector<int> > ans;
  152. for(int i=q;i;i--){
  153. if(ct[i].u!=0){
  154. int u=ct[i].u,v=ct[i].v,w=ct[i].w;
  155. split(u,v);
  156. if(w>mx[v]) continue;
  157. int gg=mpos[v];
  158. ++idx;
  159. val[idx]=w;
  160. ctt[idx].u=u,ctt[idx].v=v;
  161. cut(u,gg),cut(v,gg);
  162. link(u,idx),link(v,idx);
  163. }else{
  164. int u=Q[i].u,v=Q[i].v;
  165. split(u,v);
  166. ans.push(mx[v]);
  167. }
  168. }
  169. while(!ans.empty()){
  170. cout<<ans.top()<<"\n";
  171. ans.pop();
  172. }
  173. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注