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]之间。
Source
此题的话树链剖分是很容易看出来的……
思路比较简单,我们线段树维护的时候记录一下:
区间最前端的颜色Lc,
区间最后端的颜色Rc,
以及这个区间内的颜色段数num。
合并的时候思路也很简单,num[Left]+num[Right]-Lc[Right]==Rc[Left]。
Left和Right是一个点的左右儿子。
这样子的话线段树维护就解决了。
同时更改颜色用lazy mark。
然而还有一个问题,就是在树链剖分的求解过程中,两个节点往上跳的合并问题。
因为一会儿你在左边跳u,一会儿又在右边跳v,这个时候合并就不能简单地看上面的方法。
我们记录一个数组t[0..1],然后在左边跳的时候信息记录到t[0],右边到t[1]。
接着,根据树链剖分的模板,每次跳一个top深度更深的节点,
那么一开始设一个变量(以下称为cc)。
一开始是0,然后每次swap的时候,cc=cc xor 1.
在最后u~v更新的过程中,反过来,不swap,cc=cc xor 1.
就是跳来跳去的一种思想……然后每次可以和t[0],t[1]合并了,并且记录到t[0],t[1]。
可能说不大清楚……具体见我代码吧。
对了……就是query的时候传回来的信息其实只有上面说过的3个,但是线段树有4个(还有个mark)
懒得弄了(唔
……于是多了个mark,也不管了。
最后谈谈感想……
很坑!洛谷上提交RE,然后数组从10^5多开了一倍,就AC了……
BZOJ上提交的时候数组改成了10^5+50000,也AC了,没什么心情去测10^5能否A。
这题主要还是合并的问题……其它没什么难点吧。
坑啊!代码长,而且我的代码跑起来还出奇地慢QAQ。。。
#include<bits/stdc++.h>
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int
N=150005;
int n,m,cnt,Ecnt;
int col[N];
struct Edge{
int next,to;
}E[N<<1]; int head[N];
struct Tree{
int pre,son,deep,top,sz,tid;
}tree[N];
struct Segment{
int mark,lc,rc,numc;
}tr[N<<2];
void add(int u,int v){
E[++Ecnt].next=head[u];
E[Ecnt].to=v;
head[u]=Ecnt;
}
void up(int x){
int l=x<<1,r=x<<1|1;
tr[x].numc=tr[l].numc+tr[r].numc-(tr[l].rc==tr[r].lc);
tr[x].lc=tr[l].lc,tr[x].rc=tr[r].rc;
}
void down(int x){
if (tr[x].mark){
int l=x<<1,r=x<<1|1;
tr[l].mark=tr[r].mark=tr[x].mark;
tr[l].numc=tr[r].numc=1;
tr[l].lc=tr[l].rc=tr[r].lc=tr[r].rc=tr[x].mark;
tr[x].mark=0;
}
}
void update(int id,int l,int r,int gl,int gr,int color){
down(id);
if (l>=gl && r<=gr){
tr[id].mark=color;
tr[id].lc=tr[id].rc=color;
tr[id].numc=1;
return;
}
int mid=(l+r)>>1;
if (gr<=mid) update(id<<1,l,mid,gl,gr,color); else
if (gl>mid) update(id<<1|1,mid+1,r,gl,gr,color);
else{
update(id<<1,l,mid,gl,mid,color);
update(id<<1|1,mid+1,r,mid+1,gr,color);
}
up(id);
}
Segment query(int id,int l,int r,int gl,int gr){
down(id);
if (l>=gl && r<=gr) return {0,tr[id].lc,tr[id].rc,tr[id].numc};
int mid=(l+r)>>1;
if (gr<=mid) return query(id<<1,l,mid,gl,gr); else
if (gl>mid) return query(id<<1|1,mid+1,r,gl,gr);
else{
Segment t1=query(id<<1,l,mid,gl,mid),
t2=query(id<<1|1,mid+1,r,mid+1,gr);
return {0,t1.lc,t2.rc,t1.numc+t2.numc-(t1.rc==t2.lc)};
}
}
void build(int x,int pre,int depth){
tree[x].sz=1;
tree[x].deep=depth;
tree[x].pre=pre;
int maxx=0;
for (int i=head[x];i;i=E[i].next){
int j=E[i].to;
if (j==pre) continue;
build(j,x,depth+1);
tree[x].sz+=tree[j].sz;
if (maxx<tree[j].sz){
maxx=tree[j].sz;
tree[x].son=j;
}
}
}
void getlink(int x,int ancestor){
tree[x].top=ancestor;
tree[x].tid=++cnt;
if (tree[x].son) getlink(tree[x].son,ancestor);
for (int i=head[x];i;i=E[i].next){
int j=E[i].to;
if (j==tree[x].pre || j==tree[x].son) continue;
getlink(j,j);
}
}
void change(int u,int v,int color){
while (tree[u].top!=tree[v].top){
if (tree[tree[u].top].deep<tree[tree[v].top].deep) swap(u,v);
update(1,1,n,tree[tree[u].top].tid,tree[u].tid,color);
u=tree[tree[u].top].pre;
}
if (tree[u].deep>tree[v].deep) swap(u,v);
update(1,1,n,tree[u].tid,tree[v].tid,color);
}
int answer(int u,int v){
bool cc;
Segment t[2],tmp;
t[0]=t[1]={0,0,0,0}; //左右跳跃的数组
cc=0;
while (tree[u].top!=tree[v].top){
if (tree[tree[u].top].deep<tree[tree[v].top].deep) swap(u,v),cc^=1;
tmp=query(1,1,n,tree[tree[u].top].tid,tree[u].tid);
if (t[cc].rc) t[cc]={0,tmp.lc,t[cc].rc,tmp.numc+t[cc].numc-(tmp.rc==t[cc].lc)};
else t[cc]=tmp;
u=tree[tree[u].top].pre;
}
if (tree[u].deep>tree[v].deep) swap(u,v); else cc^=1;
tmp=query(1,1,n,tree[u].tid,tree[v].tid);
if (t[cc].rc) t[cc]={0,tmp.lc,t[cc].rc,tmp.numc+t[cc].numc-(tmp.rc==t[cc].lc)};
else t[cc]=tmp;
return t[0].numc+t[1].numc-(t[0].lc==t[1].lc);
}
int main(){
n=read(),m=read();
for (int i=1;i<=n;i++)
col[i]=read();
int x,y; Ecnt=0;
for (int i=1;i<n;i++){
x=read(),y=read();
add(x,y),add(y,x);
}
build(1,0,0);
cnt=0; getlink(1,1);
for (int i=1;i<=n;i++)
update(1,1,n,tree[i].tid,tree[i].tid,col[i]);
char opt[3];int color;
while (m--){
scanf("%s",opt);
if (opt[0]=='C'){
x=read(),y=read(),color=read();
change(x,y,color);
} else{
x=read(),y=read();
printf("%d\n",answer(x,y));
}
}
return 0;
}