题目大意:给定一棵树,树上的每个点有一个颜色
给定两种操作
Q:询问节点x到节点y路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
C:将节点x到节点y路径上所有点都染成颜色z
首先这种题一看就能反应出来是树链剖分
然后就是线段树的区间合并问题了
每个节点保存区间内的颜色段数、左端点颜色和右端点颜色
两段区间合并时,若左区间右端点和右区间左端点颜色相同,则新区间段数为左右区间之和-1
否则即为两区间之和
询问时也是这种处理方法 不过小心别把左右弄反了
本来很快就写完了 然后读入C和Q的时候忘记了Linux里的回车是'\r' 因为这点P事WA了一下午 拍了三千组数据全过了 交上去第一个点就WA 我勒个去。。。。
总之贴代码
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ls tree[p].lson #define rs tree[p].rson #define M 100100 using namespace std; struct Col{ int num,lcol,rcol; }empty; struct Tree{ Col col,mark; int lson,rson; }tree[M<<1]; struct abcd{ int to,next; }table[M<<1]; int head[M],tot=1; int n,m,fa[M],col[M],son[M],dpt[M],siz[M],pos[M],top[M],poscol[M],cnt; void add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void dfs1(int x) { int i; siz[x]=1; dpt[x]=dpt[fa[x]]+1; for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x]) continue; fa[table[i].to]=x; dfs1(table[i].to); if(siz[table[i].to]>siz[son[x]]) son[x]=table[i].to; siz[x]+=siz[table[i].to]; } } void dfs2(int x) { int i; if(son[fa[x]]==x) top[x]=top[fa[x]]; else { top[x]=x; for(i=x;i;i=son[i]) pos[i]=++cnt; } poscol[pos[x]]=col[x]; for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x]) continue; dfs2(table[i].to); } } Col operator + (Col x,Col y) { Col re; re.lcol=x.lcol; re.rcol=y.rcol; re.num=x.num+y.num-(x.rcol==y.lcol); return re; } void Build_tree(int p,int x,int y) { int mid=x+y>>1; if(x==y) { tree[p].col.num=1; tree[p].col.lcol=tree[p].col.rcol=poscol[mid]; return ; } ls=++tot;rs=++tot; Build_tree(ls,x,mid); Build_tree(rs,mid+1,y); tree[p].col=tree[ls].col+tree[rs].col; } Col getans(int p,int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) return tree[p].col; if(tree[p].mark.num) { tree[ls].col=tree[rs].col=tree[p].mark; tree[ls].mark=tree[rs].mark=tree[p].mark; tree[p].mark=empty; } if(r<=mid) return getans(ls,x,mid,l,r); if(l>mid) return getans(rs,mid+1,y,l,r); return getans(ls,x,mid,l,mid) + getans(rs,mid+1,y,mid+1,r); } int Q(int x,int y) { Col xcol=empty,ycol=empty; int fx=top[x],fy=top[y]; while(fx!=fy) { if(dpt[fx]<dpt[fy]) swap(x,y),swap(fx,fy),swap(xcol,ycol); xcol=getans(0,1,n,pos[fx],pos[x])+xcol; x=fa[fx]; fx=top[x]; } if(dpt[x]<dpt[y]) swap(x,y),swap(fx,fy),swap(xcol,ycol); xcol=getans(0,1,n,pos[y],pos[x])+xcol; return xcol.num+ycol.num-(xcol.lcol==ycol.lcol); } void change(int p,int x,int y,int l,int r,Col z) { int mid=x+y>>1; if(x==l&&y==r) { tree[p].col=z; tree[p].mark=z; return ; } if(tree[p].mark.num) { tree[ls].col=tree[rs].col=tree[p].mark; tree[ls].mark=tree[rs].mark=tree[p].mark; tree[p].mark=empty; } if(r<=mid) change(ls,x,mid,l,r,z); else if(l>mid) change(rs,mid+1,y,l,r,z); else change(ls,x,mid,l,mid,z) , change(rs,mid+1,y,mid+1,r,z); tree[p].col=tree[ls].col+tree[rs].col; } void C(int x,int y,int z) { int fx=top[x],fy=top[y]; Col zmark; zmark.num=1; zmark.lcol=zmark.rcol=z; while(fx!=fy) { if(dpt[fx]<dpt[fy]) swap(x,y),swap(fx,fy); change(0,1,n,pos[fx],pos[x],zmark); x=fa[fx]; fx=top[x]; } if(dpt[x]<dpt[y]) swap(x,y),swap(fx,fy); change(0,1,n,pos[y],pos[x],zmark); } inline char get_char() { char c; do c=getchar(); while(c=='\n'||c==' '||c=='\r'); return c; } int main() { int i,x,y,z; char p; cin>>n>>m; for(i=1;i<=n;i++) scanf("%d",&col[i]),col[i]++; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } tot=0; dfs1(1); dfs2(1); Build_tree(0,1,n); for(i=1;i<=m;i++) { p=get_char(); if(p=='Q') { scanf("%d%d",&x,&y); printf("%d\n",Q(x,y)); } else { scanf("%d%d%d",&x,&y,&z); C(x,y,z+1); } } }