2243: [SDOI2011] Ⱦɫ
Time Limit: 20 Sec
Memory Limit: 512 MBDescription
给定一棵有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 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
Sample Output 1
3
1
2HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
此题的关键是线段树记录的信息是什么
线段树上记三个量:
该段颜色段数,左端点颜色,右端点颜色
在合并的时候段点颜色要特别小心仔细
写法技巧和细节也很重要
其余树链剖分
www.cnblogs.com/AGFghy/
AC代码
#include<cstdio> #include<algorithm> using namespace std; const int N=1e5+5; int n,m,u,v,x,y,c,num,cnt; int point[N<<1],next[N<<1],head[N]; int fa[N],dep[N],size[N],son[N],id[N],top[N]; int a[N],fc[N]; char pd[5]; struct node { int lc,rc,v,lazy; }tree[N<<2]; void add(int u,int v) { point[++num]=v; next[num]=head[u]; head[u]=num; } void dfs1(int now,int pre) { fa[now]=pre; dep[now]=dep[pre]+1; size[now]=1; for (int i=head[now]; i; i=next[i]) { int v=point[i]; if (v==pre) continue; dfs1(v,now); size[now]+=size[v]; if (size[v]>size[son[now]]) son[now]=v; } } void dfs2(int now,int topf) { top[now]=topf; id[now]=++cnt; a[cnt]=fc[now]+1; if (!son[now]) return; dfs2(son[now],topf); for (int i=head[now]; i; i=next[i]) { int v=point[i]; if (v==fa[now] || v==son[now]) continue; dfs2(v,v); } } void pushup(int p) { tree[p].lc=tree[p<<1].lc; tree[p].rc=tree[(p<<1)+1].rc; tree[p].v=tree[p<<1].v+tree[(p<<1)+1].v-(tree[p<<1].rc==tree[(p<<1)+1].lc); } void pushdown(int p) { if (tree[p].lazy) { tree[p<<1].lc=tree[p<<1].rc=tree[p<<1].lazy=tree[p].lazy; tree[p<<1].v=1; tree[(p<<1)+1].lc=tree[(p<<1)+1].rc=tree[(p<<1)+1].lazy=tree[p].lazy; tree[(p<<1)+1].v=1; tree[p].lazy=0; } } void build(int l,int r,int p) { if (l==r) { tree[p].lc=tree[p].rc=a[l]; tree[p].v=1; return; } int mid=(l+r)>>1; build(l,mid,p<<1); build(mid+1,r,(p<<1)+1); pushup(p); } void update(int l,int r,int p,int s,int t,int c) { if (l==s && r==t) { tree[p].lc=tree[p].rc=tree[p].lazy=c; tree[p].v=1; return; } pushdown(p); int mid=(l+r)>>1; if (t<=mid) update(l,mid,p<<1,s,t,c); else if (s>mid) update(mid+1,r,(p<<1)+1,s,t,c); else { update(l,mid,p<<1,s,mid,c); update(mid+1,r,(p<<1)+1,mid+1,t,c); } pushup(p); } node query(int l,int r,int p,int s,int t) { if (l==s && r==t) return tree[p]; pushdown(p); int mid=(l+r)>>1; if (t<=mid) return query(l,mid,p<<1,s,t); else if (s>mid) return query(mid+1,r,(p<<1)+1,s,t); else { node res,s1,s2; s1=query(l,mid,p<<1,s,mid); s2=query(mid+1,r,(p<<1)+1,mid+1,t); res.lc=s1.lc; res.rc=s2.rc; res.v=s1.v+s2.v-(s1.rc==s2.lc); return res; } } void cover(int x,int y,int c) { while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y); update(1,n,1,id[top[x]],id[x],c); x=fa[top[x]]; } if (dep[x]>dep[y]) swap(x,y); update(1,n,1,id[x],id[y],c); } int seg(int x,int y) { int xc=-1,yc=-1,ans=0; node now; while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y),swap(xc,yc); now=query(1,n,1,id[top[x]],id[x]); ans+=now.v-(now.rc==xc); xc=now.lc; x=fa[top[x]]; } if (dep[x]>dep[y]) swap(x,y),swap(xc,yc); now=query(1,n,1,id[x],id[y]); ans+=now.v-(now.lc==xc)-(now.rc==yc); return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf("%d",&fc[i]); for (int i=1; i<n; i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs1(1,0); dfs2(1,1); build(1,n,1); while (m--) { scanf("%s",pd); if (pd[0]=='C') { scanf("%d%d%d",&x,&y,&c); c++; cover(x,y,c); } if (pd[0]=='Q') { scanf("%d%d",&x,&y); printf("%d\n",seg(x,y)); } } } ?