2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 7078 Solved: 2641
[ Submit][ Status][ Discuss]
Description
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
本来是想找树链剖分的题目做的,但是看到这题对于树链剖分来说实在是太裸了。而且上个星期打CF(CodeForces),Jon Snow那一轮,最后一题树链剖分写得整个人都不好了,我做到了随机数据可以过,但是毕竟人们可以相互hack,有些BT的数据实在是过不了,心里有阴影,表示我还是太弱(很能体会那些被tourist hack的人的体验)。于是又想起了之前,某(wo)人(ya)说几乎所有树链剖分都可以用Link Cut Tree完成,然后硬着头皮用LCT上。然后发现自己对LCT的理解确实比以前清楚太多(毕竟有了上次的教训)。
好了,言归正传。维护链上颜色块
段数,对是段数,不是颜色数量!如果是颜色数量,其实这题就变得更难了,因为左右不具有直接合并的性质,重复问题不好解决。既然是段数,那么我们就可以比较左右两段的颜色是否相同来加和统计。
真的那么简单吗?这里有一个易(wo)错(cuo)点(le),那就是在push_up的时候判断左右颜色是否相同,不是比较父亲和左右儿子的颜色,而是比较父亲和左边最右的点的颜色与父亲和右边最左的点的颜色。因为Link Cut Tree由于用了Splay,会改变节点的顺序,而这个改变对于统计颜色段来说是致命的。故左儿子并不是左边最右的,右儿子也不是。这样的话,我们除了对每个节点设置一个col,还要有lcol和rcol。
你以为注意了这些就能够撸起袖子敲代码吗?那你太嫩了……LCT里面有一个reverse操作,翻转改变左右儿子。如果你直接copy模板,那就恭喜逆WA了。由于有lcol和rcol,所以在reverse的时候,不仅要交换儿子,两个col也要交换,即做到左右两个区间完全交换。
说完了这些,就真的没别的了,按照普通的那样做,设置lazy标记、统计sum、下传rev标记,对了要用long long!!!……具体见代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<vector>
#include<queue>
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define MAX_V 100100
using namespace std;
struct Node
{
int l,r,fa,col,lazy,lcol,rcol;
long long sum;
bool rev;
} tree[MAX_V];
bool root[MAX_V],v[MAX_V];
deque<int> stack,list;
vector<int> g[MAX_V];
int n,m;
inline bool get(int x)
{
return tree[tree[x].fa].r==x;
}
inline void pushup(int x)
{
if (x)
{
tree[x].sum=tree[tree[x].l].sum+tree[tree[x].r].sum+1;
if (tree[tree[x].l].rcol==tree[x].col) tree[x].sum--; //与rcol比较
if (tree[tree[x].r].lcol==tree[x].col) tree[x].sum--; //与lcol比较
if (tree[x].l) tree[x].lcol=tree[tree[x].l].lcol; else tree[x].lcol=tree[x].col;
if (tree[x].r) tree[x].rcol=tree[tree[x].r].rcol; else tree[x].rcol=tree[x].col;
}
}
inline void reverse(int x)
{
if (x)
{
swap(tree[x].l,tree[x].r);
swap(tree[x].lcol,tree[x].rcol); //千万别忘了交换这两个
tree[x].rev^=1;
}
}
inline void update(int x,int w)
{
if (x)
{
tree[x].sum=1;
tree[x].col=tree[x].lazy=tree[x].lcol=tree[x].rcol=w;
}
}
inline void pushdown(int x)
{
if ((x)&&(tree[x].rev))
{
reverse(tree[x].l);
reverse(tree[x].r);
tree[x].rev=0;
}
if ((x)&&(tree[x].lazy))
{
update(tree[x].l,tree[x].lazy);
update(tree[x].r,tree[x].lazy);
tree[x].lazy=0;
}
}
inline void rotate(int x)
{
int fa=tree[x].fa,grand=tree[fa].fa;
if (get(x))
{
tree[fa].r=tree[x].l;
tree[tree[x].l].fa=fa;
tree[x].l=fa;
} else
{
tree[fa].l=tree[x].r;
tree[tree[x].r].fa=fa;
tree[x].r=fa;
}
tree[x].fa=grand;
tree[fa].fa=x;
if (root[fa]) root[x]=1,root[fa]=0;
else if (grand)
{
if (tree[grand].l==fa) tree[grand].l=x;
else if (tree[grand].r==fa) tree[grand].r=x;
}
pushup(fa);
}
inline void splay(int x)
{
int i=x; stack.clear();
for(;!root[i];i=tree[i].fa)
stack.push_back(i);
stack.push_back(i);
while (!stack.empty())
{
pushdown(stack.back());
stack.pop_back();
}
while (!root[x])
{
if (!root[tree[x].fa])
{
if (get(x)==get(tree[x].fa)) rotate(tree[x].fa);
else rotate(x);
}
rotate(x);
}
pushup(x);
}
inline void access(int x)
{
int y=0;
while (x)
{
splay(x);
root[y]=0;
root[tree[x].r]=1;
tree[x].r=y;
pushup(x);
y=x,x=tree[x].fa;
}
}
inline void beroot(int x)
{
access(x);
splay(x);
reverse(x);
}
inline void query(int x,int y)
{
beroot(x);
access(y);
splay(y);
printf("%lld\n",tree[y].sum);
}
inline void modify(int x,int y,int w)
{
beroot(x);
access(y);
splay(y);
update(y,w);
pushup(y);
}
inline void bfs()
{
list.push_back(1);
v[1]=1;
while (!list.empty())
{
int i=list.front();
list.pop_front();
for(int j=0;j<g[i].size();j++)
if (!v[g[i][j]])
{
list.push_back(g[i][j]);
v[g[i][j]]=1;
tree[g[i][j]].fa=i;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&tree[i].col);
tree[i].sum=1;
tree[i].lcol=tree[i].rcol=tree[i].col;
}
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
bfs();
memset(root,1,sizeof(root));
for(int i=1;i<=m;i++)
{
char ch; int x,y,z;
scanf("%s%d%d",&ch,&x,&y);
if (ch=='C')
{
scanf("%d",&z);
modify(x,y,z);
} else query(x,y);
}
}