[BZOJ3282]Tree(LCT)

3282: Tree

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 2350  Solved: 1104
[Submit][Status][Discuss]

Description

给定N个点以及每个点的权值,要你处理接下来的M个操作。

操作有4种。操作从0到3编号。点从1到N编号。

0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和。

保证x到y是联通的。

1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接。

2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。

3:后接两个整数(x,y),代表将点X上的权值变成Y。

Input

第1行两个整数,分别为N和M,代表点数和操作数。

第2行到第N+1行,每行一个整数,整数在[1,10^9]内,代表每个点的权值。

第N+2行到第N+M+1行,每行三个整数,分别代表操作类型和操作所需的量。

1<=N,M<=300000

Output

对于每一个0号操作,你须输出X到Y的路径上点权的Xor和。

Sample Input

3 3

1

2

3

1 1 2

0 1 2

0 1 1

Sample Output

3

1

HINT

Source

复习一下LCT板子。感觉异或有非常多的性质?至少异或和LCT关系比较密切。

Link-Cut Tree,一种可以支持在线维护森林以及连边,断边等森林操作的数据结构。主要难点在于区分“原树”与“Splay”树。

和Splay的区别不大,主要是Rot()和Splay()中的y!=rt改为了!isroot(y),以及Splay之前一定要记得将这棵Splay树pushdown。

注意要多upd(),修改的时候记得Splay()一下以保证期望复杂度。

for (int y=0; x; y=x,x=f[x]) splay(x),ch[x][1]=y,upd(x); 感觉是最难的一句话,要记牢。

代码应该会很难调,所以要提高熟练度和静态差错的能力。

有个奇怪的地方,在结构体内定义的函数好像可以不用分先后顺序。如下面的代码,split()用到了mkroot(),但前者可以放在后者的前面。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define ls ch[x][0]
 4 #define rs ch[x][1]
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 using namespace std;
 7
 8 const int N=300100;
 9 int n,Q,op,x,y;
10
11 struct LCT{
12     int v[N],sum[N],f[N],ch[N][2],rev[N];
13     bool isroot(int x){ return (!f[x]) || (ch[f[x]][0]!=x && ch[f[x]][1]!=x); }
14     void put(int x){ swap(ls,rs); rev[x]^=1; }
15     void push(int x){ if (rev[x]) put(ls),put(rs),rev[x]=0; }
16     void upd(int x){ sum[x]=sum[ls]^sum[rs]^v[x]; }
17     void pd(int x){ if (!isroot(x)) pd(f[x]); push(x); }
18
19     void rot(int x){
20         int y=f[x],z=f[y],w=(ch[y][1]==x);
21         if (!isroot(y)) ch[z][ch[z][1]==y]=x;
22         f[x]=z; f[y]=x; f[ch[x][w^1]]=y;
23         ch[y][w]=ch[x][w^1]; ch[x][w^1]=y; upd(y);
24     }
25
26     void splay(int x){
27         pd(x);
28         while (!isroot(x)){
29             int y=f[x],z=f[y];
30             if (!isroot(y)){ if ((ch[z][0]==y) ^ (ch[y][0]==x)) rot(x); else rot(y); }
31             rot(x);
32         }
33         upd(x);
34     }
35
36     void access(int x){ for (int y=0; x; y=x,x=f[x]) splay(x),ch[x][1]=y,upd(x); }
37     void split(int x,int y){ mkroot(x); access(y); splay(y); }
38     void mkroot(int x){ access(x); splay(x); put(x); }
39     void link(int x,int y){ mkroot(x); f[x]=y; }
40     void cut(int x,int y){ split(x,y); ch[y][0]=f[x]=0; upd(y); }
41     int find(int x){ access(x); splay(x); while (ls) x=ls; return x; }
42 }T;
43
44 int main(){
45     freopen("bzoj3282.in","r",stdin);
46     freopen("bzoj3282.out","w",stdout);
47     scanf("%d%d",&n,&Q);
48     rep(i,1,n) scanf("%d",&T.v[i]);
49     while (Q--){
50         scanf("%d%d%d",&op,&x,&y);
51         if (op==0) T.split(x,y),printf("%d\n",T.sum[y]);
52         if (op==1) if (T.find(x)!=T.find(y)) T.link(x,y);
53         if (op==2) if (T.find(x)==T.find(y)) T.cut(x,y);
54         if (op==3) T.v[x]=y,T.splay(x);
55     }
56     return 0;
57 }

原文地址:https://www.cnblogs.com/HocRiser/p/8544721.html

时间: 2024-10-05 04:13:29

[BZOJ3282]Tree(LCT)的相关文章

HDU4718 The LCIS on the Tree(LCT)

又是一枚LCT,写一发加深一下对LCT的理解.本题的坑爹之处就在于,它实在是太坑爹了.询问的是树路径上的最长连续上升的子串,考验的是怎么样去维护.一开始的想法是维护三个变量 ls,rs,mxl,分别表示左起最长上升,右末最长上升,以及总的最长上升,那么最长上升一定是可以在下面的条件下求到的, mxl=max(ch[0]->mxl,ch[1]->mxl) 以及 令temp=1 存一下左右区间的左右lval,rval, if val>ch[0]->rval temp+=ch[0]-&g

【bzoj3282】Tree LCT

题目描述 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接. 2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在. 3:后接两个整数(x,y),代表将点X上的权值变成Y. 输入 第1行两个整数,分别为N和M,代表点数和操作数. 第2行到第N+1行,每行一个整

BZOJ3282: Tree

传送门 又是权限题= =,过了NOIp我就要去当一只权限狗! LCT裸题,get到了两个小姿势. 1.LCA操作应该在access中随时updata 2.Link操作可以更简单 void Link(int noda,int nodb){Reverse(noda);t[noda].fa=nodb;} 1 //BZOJ 3282 2 //by Cydiater 3 //2016.9.16 4 #include <iostream> 5 #include <cstdio> 6 #incl

BZOJ 2631: tree( LCT )

LCT...略麻烦... -------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #define

hdu5398 GCD Tree(lct)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud GCD Tree Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 84    Accepted Submission(s): 38 Problem Description Teacher Mai has a graph w

BZOJ 3282: Tree [LCT]

3282: Tree Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1677  Solved: 744[Submit][Status][Discuss] Description 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接.

spoj 375 query on a tree LCT

这道题是树链剖分的裸题,正在学LCT,用LCT写了,发现LCT代码比树链剖分还短点(但我的LCT跑极限数据用的时间大概是kuangbin大神的树链剖分的1.6倍,所以在spoj上是850ms卡过的). 收获: 1.边转换成点(即若存在边(u,v),则新加一个点z代表边,将z连接u和v,z的点权就是(u,v)的边权,非边点的权设为-oo),然后对边权的统计就变成了对点权的统计(这是LCT中处理边信息的通法之一). 2.若要连接两个点u,v,先让它们分别称为根,然后将其中一个的path-parent

bzoj2631: tree lct

要打mul和add的lct 50000+的mod用unsigned int好了TAT (坑爹没打pc('\n');(静态)调了好久,样例竟然只输出一个,orz,也不提示PE T_T) 1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstdio> 6 7 using namespace std; 8 9 co

【BZOJ】2631: tree LCT

[题意]给定n个点的树,每个点初始权值为1,m次操作:1.x到y的点加值,2.断一条边并连一条边,保证仍是树,3.x到y的点乘值,4.x到y的点权值和取模.n,m<=10^5. [算法]Link-Cut Tree [题解]区间加和区间乘标记的处理:[BZOJ]1798: [Ahoi2009]Seq 维护序列seq 线段树 splay上维护要注意: 1.上传时加本身. 2.改值的时候不能影响到0点. 3.所有改变点的儿子的地方都要上传,所有改变点的父亲的地方都要下传. 除了rotate,还有acc