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行,每行三个整数,分别代表操作类型和操作所需的量。
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
1<=N,M<=300000
Source
动态树
LCT裸题
注意数据有可能不合法,在连边的时候要找根,重点是删边。
cut操作中,要先让一个点u为根,在access另一个点v,再对它splay,这样形成的splay只有它两个点。若它俩有边,则当前v的左儿子一定是u,u的右儿子一定没有。
不过此题好像只需要判断u和v是否在同一棵子树就可以A了……数据水……
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int SZ = 1000010;
const int INF = 1000000010;
struct node{
node *f,*ch[2];
int ans,v;
bool rev;
void maintain()
{
ans = ch[0] -> ans ^ ch[1] -> ans ^ v;
}
void setc(node *x,int d) { (ch[d] = x) -> f = this; }
void pushdown();
int dir() { return f -> ch[1] == this; }
bool isroot() { return f -> ch[0] != this && f -> ch[1] != this; }
}T[SZ], *null, *tree[SZ];
int Tcnt = 0;
node* newnode(int x)
{
node *k = T + (Tcnt ++);
k -> ch[0] = k -> ch[1] = k -> f = null;
k -> v = k -> ans = x;
k -> rev = 0;
return k;
}
void pushrev(node *p) { if(p == null) return; swap(p -> ch[0],p ->ch[1]); p -> rev ^= 1; }
void node :: pushdown()
{
if(rev) { pushrev(ch[0]); pushrev(ch[1]); rev = 0; }
}
void rotate(node *p)
{
node *fa = p -> f;
int d = p -> dir();
p -> f = fa -> f;
if(!fa -> isroot()) p -> f -> ch[fa -> dir()] = p;
fa -> ch[d] = p -> ch[d ^ 1];
if(fa -> ch[d] != null) fa -> ch[d] -> f = fa;
p -> setc(fa,d ^ 1);
fa -> maintain(); p -> maintain();
}
node *S[SZ];
void pushpath(node *p)
{
int top = 0;
while(!p -> isroot()) S[++ top] = p,p = p -> f;
S[++ top] = p;
while(top) S[top --] -> pushdown();
}
void splay(node *p)
{
pushpath(p);
while(!p -> isroot())
{
if(p -> f -> isroot()) rotate(p);
else
{
if(p -> dir() == p -> f -> dir()) rotate(p -> f),rotate(p);
else rotate(p),rotate(p);
}
}
p -> maintain();
}
void access(node *p)
{
node *last = null;
while(p != null)
{
splay(p);
p -> ch[1] = last; p -> maintain();
last = p;
p = p -> f;
}
}
void toroot(node *p)
{
access(p); splay(p); pushrev(p);
}
void link(node *u,node *v)
{
toroot(u); u -> f = v;
}
void cut(node *u,node *v)
{
toroot(u);
access(v);
splay(v);
if(v -> ch[0] == u && u -> ch[1] == null)
v -> ch[0] = u -> f = null,v -> maintain();
}
void change(node *p,int v)
{
access(p); splay(p); p -> v = v;
p -> maintain();
}
node* find_root(node *p)
{
while(p -> f != null) p = p -> f;
return p;
}
int ask_xor(node *u,node *v)
{
toroot(u);
access(v);
splay(v);
return v -> ans;
}
void init() { null = newnode(0); }
int main()
{
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++)
{
int x;
scanf("%d",&x);
tree[i] = newnode(x);
}
while(m --)
{
int opt,u,v;
scanf("%d%d%d",&opt,&u,&v);
if(opt == 0)
printf("%d\n",ask_xor(tree[u],tree[v]));
else if(opt == 1)
{
if(find_root(tree[u]) != find_root(tree[v]))
link(tree[u],tree[v]);
}
else if(opt == 2)
{
if(find_root(tree[u]) == find_root(tree[v]))
cut(tree[u],tree[v]);
}
else
{
change(tree[u],v);
}
}
return 0;
}
/*
5 2333
1 2 3 4 5
1 1 2
1 1 3
2 2 3
0 2 3
*/

本文介绍了一道关于动态树(LCT)的数据结构题目,包括输入输出格式、操作类型及示例。文章详细解释了如何通过LCT解决点权更新、路径查询等问题,并提供了完整的C++代码实现。
2795

被折叠的 条评论
为什么被折叠?



