[SDOI2011]染色
Posted sydevil
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2011]染色相关的知识,希望对你有一定的参考价值。
染色
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面n-1行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面m行每行描述一个操作:
“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 5Sample Output
3
1
2
思路:
树链剖分模板,存下一段中的左边界(And)右边界(And)出现段数
(mathfrak{Talk is cheap,show you the code.})
// #pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
# define read read1<int>()
# define Type template<typename T>
Type inline const T read1(){
T m=0;
char k=getchar();
while(('0'>k||k>'9')&&(k!='-'))k=getchar();
const bool f=(k=='-'?1:0);
if(f)k=getchar();
while('0'<=k&&k<='9')m=(m<<3)+(m<<1)+(k^48),k=getchar();
return f?-m:m;
}
# define N 100001
int rk[N],dfn[N],f[N],son[N],siz[N],top[N],d[N],tot,va[N],s,b[N<<2];
class Tem{
public:
int lx,rx,h;
Tem(int _=0,int __=0,int ___=0):lx(_),rx(__),h(___){};
Tem& operator +=(Tem r){
if(rx==r.lx)--h;
rx=r.rx;h+=r.h;
return *this;
}
Tem operator + (Tem r){return Tem(*this)+=r;}
Tem operator ~ (){return Tem(rx,lx,h);}
}v[N<<2];
int Max(int a,int b){return a>b?a:b;}
struct E{int v,n;E(){}E(int a,int b):v(a),n(b){}}G[N<<1];
void add(int u,int v,int n){
G[n]=E(v,b[u]);
b[u]=n;
G[--n]=E(u,b[v]);
b[v]=n;
}
# define ls (d<<1)
# define rs (d<<1|1)
void pushup(int d){v[d]=v[ls]+v[rs];}
void build(int l,int r,int d){
if(l==r)v[d].lx=v[d].rx=va[rk[l]],v[d].h=1;
else{
int mid=l+r>>1;
build(l,mid,ls);build(mid+1,r,rs);
pushup(d);
}
}
Tem query(int l,int r,int tl,int tr,int d){
if(l==tl&&tr==r)return v[d];
int mid=tl+tr>>1;
if(v[d].h==1)v[rs]=v[ls]=v[d];
if(r<=mid)return query(l,r,tl,mid,d<<1);
if(l>mid)return query(l,r,mid+1,tr,d<<1|1);
return query(l,mid,tl,mid,d<<1)+query(mid+1,r,mid+1,tr,d<<1|1);
}
void cover(int l,int r,int v1,int d,int tl,int tr){
if(l==tl&&r==tr)return (void)(v[d].lx=v[d].rx=v1,v[d].h=1);
int mid=tl+tr>>1;
if(v[d].h==1)v[rs]=v[ls]=v[d];
if(r<=mid)cover(l,r,v1,ls,tl,mid);
else if(l>mid)cover(l,r,v1,rs,mid+1,tr);
else cover(l,mid,v1,ls,tl,mid),cover(mid+1,r,v1,rs,mid+1,tr);
pushup(d);
}
void dfs1(int n,int fa){
f[n]=fa;siz[n]=1;
d[n]=d[fa]+1;son[n]=0;
for(int i=b[n];i;i=G[i].n)
if(G[i].v^fa){
dfs1(G[i].v,n);
siz[n]+=siz[G[i].v];
if(siz[G[i].v]>siz[son[n]])
son[n]=G[i].v;
}
}
void dfs2(int n,int k){
rk[dfn[n]=++tot]=n;
top[n]=k;
if(son[n])dfs2(son[n],k);
for(int i=b[n];i;i=G[i].n)
if(G[i].v^f[n]&&G[i].v^son[n])
dfs2(G[i].v,G[i].v);
}
Tem inquiry(int u,int v){
int tu=top[u],tv=top[v];
Tem lans(0,0,0),rans(0,0,0);
bool lfl=1,rfl=1;
while(tu^tv)
if(d[tu]>d[tv]){
if(lfl)lans=~query(dfn[tu],dfn[u],1,s,1),lfl=0;
else lans+=~query(dfn[tu],dfn[u],1,s,1);
tu=top[u=f[tu]];
}
else{
if(rfl)rans=query(dfn[tv],dfn[v],1,s,1),rfl=0;
else rans=query(dfn[tv],dfn[v],1,s,1)+rans;
tv=top[v=f[tv]];
}
if(d[u]>=d[v])
if(rfl)rans=~query(dfn[v],dfn[u],1,s,1),rfl=0;
else rans=~query(dfn[v],dfn[u],1,s,1)+rans;
else if(lfl)lans=query(dfn[u],dfn[v],1,s,1),lfl=0;
else lans+=query(dfn[u],dfn[v],1,s,1);
return !lfl?!rfl?lans+rans:lans:rans;
}
void cover(int u,int v,int k)
{
int tu=top[u],tv=top[v];
while(tu^tv)
if(d[tu]>d[tv])
{
cover(dfn[tu],dfn[u],k,1,1,s);
tu=top[u=f[tu]];
}
else
{
cover(dfn[tv],dfn[v],k,1,1,s);
tv=top[v=f[tv]];
}
if(d[u]>d[v])cover(dfn[v],dfn[u],k,1,1,s);
else cover(dfn[u],dfn[v],k,1,1,s);
}
char str[3];
int main()
{
for(int T=1;T--;){
s=read;tot=0;int m=read;
for(int i=1;i<=s;++i)va[i]=read;
memset(b,0,sizeof(b));
for(int i=1;i<s;++i)
add(read,read,i<<1);
dfs1(1,0);dfs2(1,1);
build(1,s,1);
while(m--){
scanf("%s",str);
int l=read,r=read;
if(*str=='C')cover(l,r,read);
else printf("%d
",inquiry(l,r).h);
}
}
return 0;
}
以上是关于[SDOI2011]染色的主要内容,如果未能解决你的问题,请参考以下文章