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
首先用树剖和线段树处理
这时线段树记录的信息有a[x].l表示这段区间最左边的颜色编号,a[x].r表示这段区间最右边的颜色编号,a[x].s表示颜色数
在push up的时候,a[x].s=a[ls].s+a[rs].s,如果a[ls].r==a[rs].l就说明重复计入了一个,那么就要讲a[x].s--;
在查询答案时也要注意这一点,对于分别查询的两个区间之间要进行颜色是否相同的判断,对于链与链之间也要进行相同的判断。
#include<cstdio> #include<algorithm> #define ls x<<1 #define rs x<<1|1 using namespace std; const int N=1e5+5; struct Y { int v,f,n; }y[N<<1]; struct A { int l,r,s,lz; void fz(int g) { l=r=lz=g; s=1; } }a[N<<2]; int s,ss,siz[N],fa[N],co[N],dfn[N],tou[N],hson[N],n; void add(int u,int v) { y[++s].v=v; y[s].n=y[u].f; y[u].f=s; } void dfs1(int u) { siz[u]=1; for(int i=y[u].f;i;i=y[i].n) if(y[i].v!=fa[u]) { fa[y[i].v]=u; dfs1(y[i].v); siz[u]+=siz[y[i].v]; if(siz[y[i].v]>siz[hson[u]]) hson[u]=y[i].v; } } void dfs2(int u,int to) { dfn[u]=++ss; tou[u]=to; if(hson[u]) dfs2(hson[u],to); for(int i=y[u].f;i;i=y[i].n) if(y[i].v!=hson[u]&&y[i].v!=fa[u]) dfs2(y[i].v,y[i].v); } void pd(int x,int l,int r,int mid) { if(a[x].lz) { a[ls].fz(a[x].lz),a[rs].fz(a[x].lz); a[x].lz=0; } } void chan(int x,int l,int r,int ql,int qr,int z) { if(ql<=l&&r<=qr) a[x].fz(z); else { int mid=(l+r)>>1; pd(x,l,r,mid); if(ql<=mid) chan(ls,l,mid,ql,qr,z); if(qr>mid) chan(rs,mid+1,r,ql,qr,z); a[x].l=a[ls].l;a[x].r=a[rs].r; a[x].s=a[ls].s+a[rs].s; if(a[ls].r==a[rs].l) --a[x].s; } } int askk(int x,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr) return a[x].s; int mid=(l+r)>>1,re=0; pd(x,l,r,mid); if(ql<=mid) re+=askk(ls,l,mid,ql,qr); if(qr>mid) re+=askk(rs,mid+1,r,ql,qr); if(ql<=mid&&qr>mid&&a[ls].r==a[rs].l) --re; return re; } int gc(int x,int l,int r,int wz) { if(l==r) return a[x].lz; int mid=(l+r)>>1; pd(x,l,r,mid); if(wz<=mid) return gc(ls,l,mid,wz); else return gc(rs,mid+1,r,wz); } int qu(int u,int v) { int re=0; while(tou[u]!=tou[v]) { if(dfn[u]<dfn[v]) swap(u,v); re+=askk(1,1,n,dfn[tou[u]],dfn[u]); if(gc(1,1,n,dfn[tou[u]])==gc(1,1,n,dfn[fa[tou[u]]])) --re; u=fa[tou[u]]; } if(dfn[u]<dfn[v]) swap(u,v); re+=askk(1,1,n,dfn[v],dfn[u]); return re; } int main() { int m,u,v; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&co[i]); for(int i=2;i<=n;++i) { scanf("%d%d",&u,&v); add(u,v),add(v,u); } dfs1(1); dfs2(1,1); for(int i=1;i<=n;++i) chan(1,1,n,dfn[i],dfn[i],co[i]+1); while(m--) { char c[5]; int cc; scanf("%s%d%d",c,&u,&v); if(c[0]=='Q') printf("%d\n",qu(u,v)); else { scanf("%d",&cc);++cc; while(tou[u]!=tou[v]) { if(dfn[u]<dfn[v]) swap(u,v); chan(1,1,n,dfn[tou[u]],dfn[u],cc); u=fa[tou[u]]; } if(dfn[u]<dfn[v]) swap(u,v); chan(1,1,n,dfn[v],dfn[u],cc); } } return 0; }