LCT小结

LCT真是灵活好用…

LCT的基本思想与树链剖分差不多,都是把树剖成一条条链,只不过LCT用的是SPLAY维护的,而且,SPLAY的链是会变化的,不像剖分是定死的。

LCT最重要的操作就是access(有的地方叫expose),access(po)之后就把po到树的root这条路径变成一条链。

具体实现的话,直接向上一直连就行了,效率可以证明是O(lgn)的。

还有就是两个操作,link和cut。

cut不难,直接找到这条边断掉即可。

link的话,因为splay是用深度维护的,我们只需要access其中一个点,然后再将这个点打上翻转记号,这个点就会成为其所在的树的根,再将其接到另外一个点之下,就行了。

接下来是代码,因为前段时间BZ倒了,所以直接上的是伍一鸣的tree。

这题就是一个裸的LCT,splay上标记的打法与BZ的某道线段树题奇像。

Tsinsen1303/BZOJ2631

  1 /**************************************************************

  2     Problem: 2631

  3     User: zhuohan123

  4     Language: C++

  5     Result: Accepted

  6     Time:12260 ms

  7     Memory:9836 kb

  8 ****************************************************************/

  9  

 10 #include <iostream>

 11 #include <cstdio>

 12 #include <cstring>

 13 #include <algorithm>

 14 using namespace std;

 15 typedef unsigned int uint;

 16 const int mod=51061;

 17 int n,q;

 18 struct node

 19 {

 20     int f,s[2],ws,size;//splay tree

 21     int head;//tree

 22     bool rev;

 23     uint num,sum,add,mul;

 24 }p[110000];int pnum,root;

 25 struct edge{int to,next;}g[210000];int gnum;

 26 inline void addedge(int from,int to)

 27 {

 28     g[++gnum].to=to;g[gnum].next=p[from].head;p[from].head=gnum;

 29 }

 30  

 31 inline void iadd(uint &x,uint y){x=(x+y)%mod;}

 32 inline void imul(uint &x,uint y){x=(x*y)%mod;}

 33 inline void modify(int po,uint m,uint a)

 34 {

 35     if(m!=1)

 36     {

 37         imul(p[po].num,m);

 38         imul(p[po].sum,m);

 39         imul(p[po].mul,m);

 40         imul(p[po].add,m);

 41     }

 42     if(a)

 43     {

 44         iadd(p[po].num,a);

 45         iadd(p[po].sum,a*p[po].size%mod);

 46         iadd(p[po].add,a);

 47     }

 48 }

 49 inline void reverse(int po)

 50 {

 51     if(p[po].rev)

 52     {

 53         swap(p[po].s[0],p[po].s[1]);

 54         if(p[po].s[0])p[p[po].s[0]].rev^=1,p[p[po].s[0]].ws^=1;

 55         if(p[po].s[1])p[p[po].s[1]].rev^=1,p[p[po].s[1]].ws^=1;

 56         p[po].rev^=1;

 57     }

 58 }

 59 inline void pushdown(int po)

 60 {

 61     if(p[po].mul!=1||p[po].add!=0)

 62     {

 63         if(p[po].s[0])modify(p[po].s[0],p[po].mul,p[po].add);

 64         if(p[po].s[1])modify(p[po].s[1],p[po].mul,p[po].add);

 65         p[po].mul=1;p[po].add=0;

 66     }

 67 }

 68 inline void maintain(int po)

 69 {

 70     p[po].sum=p[po].num;

 71     if(p[po].s[0])iadd(p[po].sum,p[p[po].s[0]].sum);

 72     if(p[po].s[1])iadd(p[po].sum,p[p[po].s[1]].sum);

 73     p[po].size=1;

 74     if(p[po].s[0])p[po].size+=p[p[po].s[0]].size;

 75     if(p[po].s[1])p[po].size+=p[p[po].s[1]].size;

 76 }

 77 inline void setson(int f,int s,bool ws){p[f].s[ws]=s;p[s].f=f;p[s].ws=ws;}

 78 inline bool isroot(int po)

 79 {

 80     return !p[po].f||(p[p[po].f].s[0]!=po&&p[p[po].f].s[1]!=po);

 81 }

 82 inline void rotate(int po,bool ws)

 83 {

 84     int son=p[po].s[ws];

 85     if(isroot(po))p[son].f=p[po].f;

 86     else setson(p[po].f,son,p[po].ws);

 87     setson(po,p[son].s[!ws],ws);

 88     setson(son,po,!ws);

 89     maintain(po);maintain(son);

 90 }

 91 inline int splay(int po)

 92 {

 93     while(!isroot(po))

 94     {

 95         int fa=p[po].f,gf=p[fa].f;

 96         reverse(gf);reverse(fa);reverse(po);

 97         pushdown(gf);pushdown(fa);pushdown(po);

 98         if(isroot(fa)){rotate(fa,p[po].ws);break;}

 99         if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);

100         rotate(fa,p[po].ws);

101     }

102     reverse(po);

103     pushdown(po);

104     maintain(po);

105     return po;

106 }

107 inline void access(int po)

108 {

109     for(int last=0;po;last=po,po=p[po].f)

110     {

111         splay(po);

112         setson(po,last,1);

113         maintain(po);

114     }

115 }

116 inline void makeroot(int po)

117 {

118     access(po);

119     splay(po);

120     p[po].rev^=1;

121 }

122 inline void link(int u,int v)

123 {

124     makeroot(u);

125     p[u].f=v;

126 }

127 inline void cut(int u,int v)

128 {

129     access(v);

130     splay(u);

131     if(p[u].f==v)p[u].f=0;

132     else

133     {

134         access(u);splay(v);

135         p[v].f=0;

136     }

137 }

138 inline void change(int u,int v,uint m,uint a)

139 {

140     access(v);

141     for(int last=0;u;last=u,u=p[u].f)

142     {

143         splay(u);

144         if(!p[u].f)

145         {

146             if(last)modify(last,m,a);

147             if(p[u].s[1])modify(p[u].s[1],m,a);

148             imul(p[u].num,m);

149             iadd(p[u].num,a);

150         }

151         setson(u,last,1);

152         maintain(u);

153     }

154 }

155 inline uint getans(int u,int v)

156 {

157     access(v);

158     for(int last=0;u;last=u,u=p[u].f)

159     {

160         splay(u);

161         if(!p[u].f)

162         {

163             uint ans=p[u].num;

164             if(last)iadd(ans,p[last].sum);

165             if(p[u].s[1])iadd(ans,p[p[u].s[1]].sum);

166             return ans;

167         }

168         setson(u,last,1);

169         maintain(u);

170     }

171 }

172 void dfs(int po)

173 {

174     p[po].s[0]=p[po].s[1]=p[po].add=p[po].rev=0;

175     p[po].num=p[po].sum=p[po].mul=p[po].size=1;

176     for(int i=p[po].head;i;i=g[i].next)

177         if(g[i].to!=p[po].f)

178         {

179             p[g[i].to].f=po;

180             dfs(g[i].to);

181         }

182 }

183 int main(int argc, char *argv[])

184 {

185     //freopen("1.in","r",stdin);freopen("1.out","w",stdout);

186     scanf("%d%d",&n,&q);

187     for(int i=1;i<n;i++)

188     {

189         int u,v;scanf("%d%d",&u,&v);

190         addedge(u,v);addedge(v,u);

191     }

192     dfs(1);

193     while(q--)

194     {

195         char op[5];scanf("%s",op);

196         if(op[0]=='+')

197         {

198             int u,v,num;scanf("%d%d%d",&u,&v,&num);

199             change(u,v,1,num%mod);

200         }

201         if(op[0]=='*')

202         {

203             int u,v,num;scanf("%d%d%d",&u,&v,&num);

204             change(u,v,num%mod,0);

205         }

206         if(op[0]=='-')

207         {

208             int u1,v1,u2,v2;scanf("%d%d%d%d",&u1,&v1,&u2,&v2);

209             cut(u1,v1);link(u2,v2);

210         }

211         if(op[0]=='/')

212         {

213             int u,v;scanf("%d%d",&u,&v);

214             printf("%d\n",getans(u,v));

215         }

216     }

217     return 0;

218 }

还有一道是山东08年的省选题,就是LCT的模板题。

题意相当于维护一个带删除的并查集。

两个点是否在一个子树的判断,只需让两个点都一直沿着它的father跳,最后都会停在它所在的树的根所在的splay的根(好绕!!),只需判断这两个点是否相等即可。

BZOJ2049

 1 /**************************************************************

 2     Problem: 2049

 3     User: zhuohan123

 4     Language: C++

 5     Result: Accepted

 6     Time:1244 ms

 7     Memory:4560 kb

 8 ****************************************************************/

 9  

10 #include <iostream>

11 #include <cstdio>

12 #include <cstring>

13 #include <algorithm>

14 using namespace std;

15 struct node{int f,s[2];bool ws,rev;}p[210000];

16 inline bool isroot(int po){return (!p[po].f)||(p[p[po].f].s[0]!=po&&p[p[po].f].s[1]!=po);}

17 inline void setson(int f,int s,bool ws){p[s].f=f;p[f].s[ws]=s;p[s].ws=ws;}

18 inline void rotate(int po,bool ws)

19 {

20     int son=p[po].s[ws];

21     if(isroot(po))p[son].f=p[po].f;

22     else setson(p[po].f,son,p[po].ws);

23     setson(po,p[son].s[!ws],ws);

24     setson(son,po,!ws);

25 }

26 inline void reverse(int po)

27 {

28     if(p[po].rev)

29     {

30         swap(p[po].s[0],p[po].s[1]);

31         p[p[po].s[0]].ws^=1;

32         p[p[po].s[1]].ws^=1;

33         p[p[po].s[0]].rev^=1;

34         p[p[po].s[1]].rev^=1;

35         p[po].rev=false;

36     }

37 }

38 inline int splay(int po)

39 {

40     while(!isroot(po))

41     {

42         int fa=p[po].f,gf=p[fa].f;

43         reverse(gf);reverse(fa);reverse(po);

44          

45         if(isroot(fa)){rotate(fa,p[po].ws);break;}

46         if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);

47         rotate(fa,p[po].ws);

48     }

49     reverse(po);

50     return po;

51 }

52 inline void access(int po)

53 {

54     for(int last=0;po;last=po,po=p[po].f)

55         setson(splay(po),last,1);

56 }

57 inline void makeroot(int po)

58 {

59     access(po);splay(po);

60     p[po].rev^=1;

61 }

62 inline void link(int u,int v)

63 {

64     makeroot(u);p[u].f=v;

65 }

66 inline void cut(int u,int v)

67 {

68     access(u);splay(v);

69     if(p[v].f==u)p[v].f=0;

70     else

71     {

72         access(v);splay(u);

73         p[u].f=0;

74     }

75 }

76 inline bool check(int u,int v)

77 {

78     while(p[u].f)u=p[u].f;

79     while(p[v].f)v=p[v].f;

80     return u==v;

81 }

82 int main(int argc, char *argv[])

83 {

84     int n,m;scanf("%d%d",&n,&m);

85     while(m--)

86     {

87         char str[30];int u,v;

88         scanf("%s%d%d",str,&u,&v);

89         if(str[0]=='C')link(u,v);

90         if(str[0]=='D')cut(u,v);

91         if(str[0]=='Q')puts(check(u,v)?"Yes":"No");

92     }

93     return 0;

94 }

 接下来是最后一个……WC2006的水管局长

题意是维护一个带link与cut的最小生成树…

由于这棵树是会“动”的,所以不能把边权下放到点上,那么就只好把一条边变成一个点,再把这个点与两个端点相连,常数狂增不止。

BZOJ2494

  1 /**************************************************************

  2     Problem: 2594

  3     User: zhuohan123

  4     Language: C++

  5     Result: Accepted

  6     Time:15728 ms

  7     Memory:53252 kb

  8 ****************************************************************/

  9  

 10 #include <iostream>

 11 #include <cstdio>

 12 #include <cstring>

 13 #include <algorithm>

 14 using namespace std;

 15 inline int getnum()

 16 {

 17     int ans=0;char ch=getchar();

 18     while(ch>'9'||ch<'0')ch=getchar();

 19     while(ch>='0'&&ch<='9')ans=ans*10+ch-'0',ch=getchar();

 20     return ans;

 21 }

 22 int n,m,que;

 23 struct point

 24 {

 25     int f,s[2];bool ws,rev;

 26     int num,mnum,mpos;

 27     void output(int now)

 28     {

 29         printf("%d f:%d ls:%d rs:%d rev:%d num:%d mnum:%d mpos:%d\n",now,f,s[0],s[1],rev,num,mnum,mpos);

 30     }

 31 }p[510000];int pnum;

 32 inline void maintain(int po)

 33 {

 34     p[po].mnum=p[po].num;p[po].mpos=po;

 35     if(p[po].s[1]&&p[p[po].s[1]].mnum>p[po].mnum)

 36         p[po].mnum=p[p[po].s[1]].mnum,p[po].mpos=p[p[po].s[1]].mpos;

 37     if(p[po].s[0]&&p[p[po].s[0]].mnum>p[po].mnum)

 38         p[po].mnum=p[p[po].s[0]].mnum,p[po].mpos=p[p[po].s[0]].mpos;

 39 }

 40 inline bool isroot(int po){return (!p[po].f)||(p[p[po].f].s[0]!=po&&p[p[po].f].s[1]!=po);}

 41 inline void setson(int f,int s,bool ws){p[f].s[ws]=s;p[s].f=f;p[s].ws=ws;}

 42 inline void rotate(int po,bool ws)

 43 {

 44     int son=p[po].s[ws];

 45     if(isroot(po))p[son].f=p[po].f;

 46     else setson(p[po].f,son,p[po].ws);

 47     setson(po,p[son].s[!ws],ws);

 48     setson(son,po,!ws);

 49     maintain(po);maintain(son);

 50 }

 51 inline void reverse(int po)

 52 {

 53     if(p[po].rev)

 54     {

 55         swap(p[po].s[0],p[po].s[1]);

 56         p[p[po].s[0]].ws^=1;

 57         p[p[po].s[1]].ws^=1;

 58         p[p[po].s[0]].rev^=1;

 59         p[p[po].s[1]].rev^=1;

 60         p[po].rev=false;

 61     }

 62 }

 63 inline int splay(int po)

 64 {

 65     while(!isroot(po))

 66     {

 67         int fa=p[po].f,gf=p[fa].f;

 68         reverse(gf);reverse(fa);reverse(po);

 69         if(isroot(fa)){rotate(fa,p[po].ws);break;}

 70         if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);

 71         rotate(fa,p[po].ws);

 72     }

 73     reverse(po);

 74     return po;

 75 }

 76 inline void access(int po)

 77 {

 78     for(int last=0;po;last=po,po=p[po].f)

 79     {

 80         splay(po);

 81         setson(po,last,1);

 82         maintain(po);

 83     }

 84 }

 85 inline void makeroot(int po)

 86 {

 87     access(po);splay(po);

 88     p[po].rev^=1;

 89 }

 90 inline void link(int u,int v)

 91 {

 92     makeroot(u);p[u].f=v;

 93 }

 94 inline void cut(int u,int v)

 95 {

 96     access(u);splay(v);

 97     if(p[v].f==u)p[v].f=0;

 98     else

 99     {

100         access(v);splay(u);

101         p[u].f=0;

102     }

103 }

104 inline int getmax(int u,int v,int &mpos)

105 {

106     access(v);

107     for(int last=0;u;last=u,u=p[u].f)

108     {

109         splay(u);

110         if(!p[u].f)

111         {

112             int ans=p[u].num;mpos=u;

113             if(p[u].s[1]&&ans<p[p[u].s[1]].mnum)ans=p[p[u].s[1]].mnum,mpos=p[p[u].s[1]].mpos;

114             if(last&&ans<p[last].mnum)ans=p[last].mnum,mpos=p[last].mpos;

115             return ans;

116         }

117         setson(u,last,1);

118         maintain(u);

119     }

120     return 0; 

121 }

122 struct bian{int u,v,c,can;}b[1100000];

123 inline bool cmp1(bian a,bian b){return a.u==b.u?a.v<b.v:a.u<b.u;}

124 inline bool cmp2(bian a,bian b){return a.c<b.c;}

125 struct question{int p,u,v,pos,c,ans;}q[110000];

126 inline bool cmp3(question a,question b){return a.u==b.u?a.v<b.v:a.u<b.u;}

127 inline bool cmp4(question a,question b){return a.pos<b.pos;}

128 int fa[210000];

129 int gf(int po){return fa[po]==po?po:fa[po]=gf(fa[po]);}

130 int head[510000];

131 struct edge{int to,next;}g[1100000];int gnum;

132 inline void addedge(int from,int to)

133 {

134     g[++gnum].to=to;g[gnum].next=head[from];head[from]=gnum;

135     g[++gnum].to=from;g[gnum].next=head[to];head[to]=gnum;

136 }

137 bian intree[310000];

138 int qu[510000],ql,qr;

139 void bfs()

140 {

141     ql=1;qr=0;

142     qu[++qr]=1;

143     while(ql<=qr)

144         for(int now=qu[ql++],i=head[now];i;i=g[i].next)

145         if(p[now].f!=g[i].to)

146         p[qu[++qr]=g[i].to].f=now;

147 }

148 int main(int argc, char *argv[])

149 {

150     //freopen("1.in","r",stdin);

151     //freopen("1.out","w",stdout);

152     n=getnum(),m=getnum(),que=getnum();

153     pnum=n;

154     for(int i=1;i<=m;i++)

155     {

156         b[i].u=getnum(),b[i].v=getnum(),b[i].c=getnum();

157         if(b[i].u>b[i].v)swap(b[i].u,b[i].v);

158         b[i].can=true;

159     }

160     for(int i=1;i<=que;i++)

161     {

162         q[i].p=getnum(),q[i].u=getnum(),q[i].v=getnum();

163         if(q[i].u>q[i].v)swap(q[i].u,q[i].v);

164         q[i].pos=i;

165     }

166     sort(b+1,b+m+1,cmp1);

167     sort(q+1,q+que+1,cmp3);

168     for(int i=1,j=1;i<=m&&j<=que;i++)

169     {

170         while(j<=que&&((q[j].u<b[i].u)||(q[j].u==b[i].u&&q[j].v<b[i].v)||q[j].p==1))j++;

171         if(j<=que&&q[j].u==b[i].u&&q[j].v==b[i].v)b[i].can=false,q[j].c=b[i].c;

172     }

173     for(int i=1;i<=n;i++)fa[i]=i;

174     sort(b+1,b+m+1,cmp2);

175     for(int i=1;i<=m;i++)

176     if(b[i].can&&gf(b[i].u)!=gf(b[i].v))

177     {

178         pnum++;p[pnum].num=b[i].c;

179         addedge(b[i].u,pnum);

180         addedge(b[i].v,pnum);

181         intree[pnum].u=b[i].u;intree[pnum].v=b[i].v;

182         fa[gf(b[i].u)]=gf(b[i].v);

183     }

184     bfs();

185     for(int i=1;i<=pnum;i++)p[i].mnum=p[i].num,p[i].mpos=i;

186     sort(q+1,q+que+1,cmp4);

187     for(int i=que;i;i--)

188     {

189         int mpos;

190         if(q[i].p==1)q[i].ans=getmax(q[i].u,q[i].v,mpos);

191         else if(getmax(q[i].u,q[i].v,mpos)>q[i].c)

192         {

193             cut(mpos,intree[mpos].u);

194             cut(mpos,intree[mpos].v);

195             intree[mpos].u=q[i].u;

196             intree[mpos].v=q[i].v;

197             p[mpos].num=q[i].c;

198             link(mpos,q[i].u);

199             link(mpos,q[i].v);

200         }

201     }

202     for(int i=1;i<=que;i++)

203         if(q[i].p==1)printf("%d\n",q[i].ans);

204     return 0;

205 }

 

你可能感兴趣的:(小结)