2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9399 Solved: 3528
[ 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]之间。
思路&&分析
这道题,通过分析题意,由于它的操作是树上路径颜色覆盖,然后查询一段路径上的颜色段数,那么对于这种树上路径操作的题我们很多都可以通过树剖来解决。我在树剖后用的是线段树来维护答案,我们线段树要维护这一段的颜色段数,左端点颜色和右端点颜色,对于线段树的update合并左右两段的颜色数时,要注意当左孩子的右端点颜色和右孩子的左端点颜色相同时,该点的sum应该是左右孩子的sum和减1,。然后这一点在树剖上分段查询的时候也需要注意。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
#define ls o<<1
#define rs o<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
const int maxn=200010;
vector<int>G[maxn];
int n,m,son[maxn],fa[maxn],dep[maxn],id[maxn],sz[maxn],v[maxn],nw[maxn],tp[maxn],dfs_clock;
struct seg {
int sum,lef,rig,lazy;
inline void init() {
sum=lef=rig=lazy=0;
}
}t[maxn<<2];
inline void dfs1(int u) {
sz[u]=1;
for(unsigned i=0;i<G[u].size();i++) {
int v=G[u][i];
if(v==fa[u])
continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
sz[u]+=sz[v];
if(!son[u]||sz[son[u]]<sz[v])
son[u]=v;
}
}
inline void dfs2(int u,int p) {
tp[u]=p;
id[u]=++dfs_clock;
nw[id[u]]=v[u];
if(!son[u])
return;
dfs2(son[u],p);
for(unsigned i=0;i<G[u].size();i++) {
int v=G[u][i];
if(v==son[u]||v==fa[u])
continue;
dfs2(v,v);
}
}
inline void pushup(int o) {
t[o].sum=t[ls].sum+t[rs].sum;
t[o].lef=t[ls].lef;
t[o].rig=t[rs].rig;
if(t[ls].rig==t[rs].lef)
t[o].sum--;
}
inline void pushdown(int o,int l,int r) {
if(t[o].lazy) {
t[ls].sum=t[rs].sum=1;
t[ls].lef=t[ls].rig=t[rs].lef=t[rs].rig=t[o].lazy;
t[ls].lazy=t[rs].lazy=t[o].lazy;
t[o].lazy=0;
}
}
inline void build(int o,int l,int r) {
t[o].init();
if(l==r) {
t[o].sum=1;
t[o].lef=t[o].rig=nw[l];
return;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
pushup(o);
}
inline void update(int o,int l,int r,int ql,int qr,int w) {
// cout<<t[o].sum<<" "<<t[o].lef<<" "<<t[o].rig<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<endl;
pushdown(o,l,r);
if(l==ql&&r==qr) {
t[o].sum=1;
t[o].lazy=w;
t[o].lef=t[o].rig=w;
return;
}
int mid=(l+r)>>1;
if(qr<=mid)
update(lson,ql,qr,w);
else if(ql>mid)
update(rson,ql,qr,w);
else {
update(lson,ql,mid,w);
update(rson,mid+1,qr,w);
}
pushup(o);
}
inline seg query(int o,int l,int r,int ql,int qr) {
pushdown(o,l,r);
if(l==ql&&r==qr)
return t[o];
int mid=(l+r)>>1;
if(qr<=mid)
return query(lson,ql,qr);
else if(ql>mid)
return query(rson,ql,qr);
else {
seg le=query(lson,ql,mid),ri=query(rson,mid+1,qr),res;
res.sum=le.sum+ri.sum-(le.rig==ri.lef);
res.lef=le.lef;res.rig=ri.rig;
return res;
}
}
inline int subque(int x,int y) {
seg now;
int res=0,lx=-1,ly=-1;
while(tp[x]!=tp[y]) {
if(dep[tp[x]]<dep[tp[y]]) {
swap(x,y);
swap(lx,ly);
}
now=query(1,1,n,id[tp[x]],id[x]);
res+=now.sum-(now.rig==lx);
lx=now.lef;
x=fa[tp[x]];
}
if(dep[x]>dep[y]) {
swap(x,y);
swap(lx,ly);
}
now=query(1,1,n,id[x],id[y]);
res+=now.sum-(now.lef==lx)-(now.rig==ly);
return res;
}
inline void subupd(int x,int y,int w) {
while(tp[x]!=tp[y]) {
if(dep[tp[x]]<dep[tp[y]])
swap(x,y);
update(1,1,n,id[tp[x]],id[x],w);
x=fa[tp[x]];
}
if(dep[x]>dep[y])
swap(x,y);
update(1,1,n,id[x],id[y],w);
}
int main() {
read(n);read(m);
for(int i=1;i<=n;i++)
read(v[i]);
for(int i=1,u,v;i<n;i++) {
read(u);read(v);
G[u].push_back(v);
G[v].push_back(u);
}
dep[1]=1,fa[1]=-1;
dfs1(1);
dfs2(1,1);
build(1,1,n);
while(m--) {
char op[2];
int a,b,c;
scanf("%s",op+1);
read(a);read(b);
if(op[1]=='Q')
printf("%d\n",subque(a,b));
else {
read(c);
subupd(a,b,c);
}
}
}