题目:
题目背景
SDOI2011 DAY1 T3
题目描述
给定一棵有 n 个节点的无根树和 m 个操作,操作有 2 类:
1、将节点 a 到节点 b 路径上所有点都染成颜色 c ;
2、询问节点 a 到节点 b 路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由 3 段组:“11”、“222”和“1”。
请你写一个程序依次完成这 m 个操作。
输入格式
第一行包含 2 个整数 n 和 m ,分别表示节点数和操作数;
第二行包含 n 个正整数表示 n 个节点的初始颜色;
下面 n-1 行每行包含两个整数 x 和 y ,表示 x 和 y 之间有一条无向边。
下面 m 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点 a 到节点 b 路径上所有点(包括a和b)都染成颜色;
“Q a b”表示这是一个询问操作,询问节点 a 到节点 b(包括a和b)路径上的颜色段数量。
输出格式
对于每个询问操作,输出一行答案。
样例数据 1
输入 [复制]
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
输出
3
1
2
备注
【数据范围】
对于测试点 7、8、9、10,树是这样生成的:
随机生成一个 1~n 的排列 p ,设 p1为根。对于2≤i≤n,pi 的父亲为 Prandom(1,i-1),其中 Prandom(a,b)以相等的概率返回 {x∈Z|a≤x≤b}中的一个元素,然后将所有边打乱顺序后作为输入提供给你的程序。
【友情提示】
不允许使用编译开关改变栈空间大小,请选手尽量不要使用递归,以避免堆栈溢出。
题解:
树链剖分题···注意维护线段树时的一些小细节即可
代码:
#include#include #include #include #include #include #include #include<string> using namespace std; const int N=1e5+5; int first[N],go[N*2],next[N*2],son[N],size[N],idx[N],pos[N],father[N],deep[N],top[N],tot; int color[N],Left[N*4],Right[N*4],num[N*4],cnt,n,m,lazy[N*4]; inline int R() { char c;int f=0; for(c=getchar();c<'0'||c>'9';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) f=(f<<3)+(f<<1)+c-'0'; return f; } inline void comb(int a,int b) { next[++tot]=first[a],first[a]=tot,go[tot]=b; next[++tot]=first[b],first[b]=tot,go[tot]=a; } inline void dfs1(int u,int fa) { size[u]=1; for(int e=first[u];e;e=next[e]) { int v=go[e]; if(v==fa) continue; father[v]=u;deep[v]=deep[u]+1; dfs1(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } } inline void dfs2(int u) { if(son[u]) { idx[pos[son[u]]=++cnt]=son[u]; top[son[u]]=top[u]; dfs2(son[u]); } for(int e=first[u];e;e=next[e]) { int v=go[e]; if(v==father[u]||v==son[u]) continue; idx[pos[v]=++cnt]=v;top[v]=v; dfs2(v); } } inline void build(int k,int l,int r) { if(l==r) { num[k]=1; Right[k]=Left[k]=color[idx[l]]; return; } int mid=(l+r)/2; build(k*2,l,mid);build(k*2+1,mid+1,r); Right[k]=Right[k*2+1];Left[k]=Left[k*2]; if(Right[k*2]==Left[k*2+1]) num[k]=num[k*2]+num[k*2+1]-1; else num[k]=num[k*2]+num[k*2+1]; } inline void tag(int k,int c) { Left[k]=Right[k]=c; num[k]=1; lazy[k]=c; } inline void pushdown(int k) { if(lazy[k]!=-1) { tag(k*2,lazy[k]); tag(k*2+1,lazy[k]); lazy[k]=-1; } } inline void modify(int k,int l,int r,int x,int y,int c) { if(l>=x&&y>=r) { tag(k,c); return; } int mid=(l+r)/2; pushdown(k); if(x<=mid) modify(k*2,l,mid,x,y,c); if(y>mid) modify(k*2+1,mid+1,r,x,y,c); Right[k]=Right[k*2+1];Left[k]=Left[k*2]; if(Right[k*2]==Left[k*2+1]) num[k]=num[k*2]+num[k*2+1]-1; else num[k]=num[k*2]+num[k*2+1]; } inline int query(int k,int l,int r,int x,int y) { if(l>=x&&y>=r) return num[k]; int mid=(r+l)/2; pushdown(k); int ans=0; if(x<=mid) ans+=query(k*2,l,mid,x,y); if(y>mid) ans+=query(k*2+1,mid+1,r,x,y); if(Right[k*2]==Left[k*2+1]&&x<=mid&&y>mid) return ans-1; else return ans; } inline void modifypath(int a,int b,int c) { if(top[a]!=top[b]) { if(deep[top[a]]<deep[top[b]]) swap(a,b); modify(1,1,n,pos[top[a]],pos[a],c); modifypath(father[top[a]],b,c); } else { if(deep[a]<deep[b]) swap(a,b); modify(1,1,n,pos[b],pos[a],c); } } inline int queryc(int k,int l,int r,int x) { if(l==r) return Left[k]; int mid=(l+r)/2; pushdown(k); if(x<=mid) return queryc(k*2,l,mid,x); else return queryc(k*2+1,mid+1,r,x); } inline int querypath(int a,int b) { if(top[a]!=top[b]) { if(deep[top[a]]<deep[top[b]]) swap(a,b); if(queryc(1,1,n,pos[top[a]])==queryc(1,1,n,pos[father[top[a]]])) return querypath(father[top[a]],b)+query(1,1,n,pos[top[a]],pos[a])-1; else return querypath(father[top[a]],b)+query(1,1,n,pos[top[a]],pos[a]); } else { if(deep[a]<deep[b]) swap(a,b); return query(1,1,n,pos[b],pos[a]); } } int main() { //freopen("a.in","r",stdin); n=R(),m=R();int a,b,c;char s[5]; for(int i=1;i<=n*4;i++) lazy[i]=-1; for(int i=1;i<=n;i++) color[i]=R(); for(int i=1;i ) { a=R(),b=R(); comb(a,b); } dfs1(1,0); pos[1]=top[1]=idx[1]=cnt=1; dfs2(1); build(1,1,n); while(m--) { scanf("%s",s); if(s[0]=='C') { a=R(),b=R(),c=R(); modifypath(a,b,c); } else { a=R(),b=R(); cout< endl; } } return 0; }