洛谷 P2486 [SDOI2011]染色
作者:互联网
链接:
题意:
给出一棵树,节点有颜色,需要支持树链覆盖颜色,树链查询颜色段。
分析:
因为是树链操作所以考虑树链剖分,考虑在线段树上维护三个信息:当前区间最左端颜色,当前区间最右端颜色,当前区间颜色段数。pushup 时最前两个直接继承,颜色段是左右颜色段相加,同时判断左右区间中间相连部分的颜色,相同则颜色段数要减 1。线段树上查询时要开个结构体同时返回三种信息。在查询树链中,跳链时也要进行和 pushup 类似的判断。其他地方与模板区别不大。细节较多。
代码:
#include<bits/stdc++.h>
using namespace std;
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
return p*f;
}
const int N=1e5+5;
int n,m,r;
int w[N];
struct egde{
int v,next;
}e[N<<1];
int head[N],en;
void insert(int u,int v){
e[++en].v=v;
e[en].next=head[u];
head[u]=en;
}
int fa[N],dep[N],size[N],hson[N],top[N],ttol[N],ltot[N],tot;
void dfs1(int u,int f){
fa[u]=f;dep[u]=dep[f]+1;size[u]=1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(v==f)continue;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[hson[u]])
hson[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp;
ttol[u]=++tot;
ltot[tot]=u;
if(hson[u])dfs2(hson[u],tp);
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(v==fa[u]||v==hson[u])continue;
dfs2(v,v);
}
}
int sum[N<<2],tag[N<<2],lc[N<<2],rc[N<<2];
inline void pushup(int p){
sum[p]=sum[p<<1]+sum[p<<1|1]-(rc[p<<1]==lc[p<<1|1]);
lc[p]=lc[p<<1];
rc[p]=rc[p<<1|1];
}
inline void f(int p,int d){
sum[p]=1;
tag[p]=d;
lc[p]=rc[p]=d;
}
inline void pushdown(int l,int r,int p){
if(tag[p]){
int mid=(l+r)>>1;
f(p<<1,tag[p]);
f(p<<1|1,tag[p]);
tag[p]=0;
}
}
void built(int l,int r,int p){
if(l==r){
sum[p]=1,lc[p]=rc[p]=w[ltot[l]];
return ;
}
int mid=(l+r)>>1;
built(l,mid,p<<1);
built(mid+1,r,p<<1|1);
pushup(p);
}
void change(int l,int r,int p,int cl,int cr,int d){
if(l>=cl&&r<=cr){
f(p,d);
return ;
}
pushdown(l,r,p);
int mid=(l+r)>>1;
if(cl<=mid)change(l,mid,p<<1,cl,cr,d);
if(cr>mid)change(mid+1,r,p<<1|1,cl,cr,d);
pushup(p);
}
struct ret{
int l,r,sum;
};
ret query(int l,int r,int p,int ql,int qr){
if(l>=ql&&r<=qr)
return {lc[p],rc[p],sum[p]};
pushdown(l,r,p);
int mid=(l+r)>>1;
if(ql<=mid&&qr>mid){
ret t1=query(l,mid,p<<1,ql,qr),t2=query(mid+1,r,p<<1|1,ql,qr);
return {t1.l,t2.r,t1.sum+t2.sum-(t1.r==t2.l)};
}
else if(ql<=mid)return query(l,mid,p<<1,ql,qr);
else return query(mid+1,r,p<<1|1,ql,qr);
}
void changeit(int x,int y,int d){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
change(1,n,1,ttol[top[x]],ttol[x],d);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
change(1,n,1,ttol[x],ttol[y],d);
}
int queryit(int x,int y){
int res=0,lastx=0,lasty=0;
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]]){
ret t=query(1,n,1,ttol[top[x]],ttol[x]);
res+=t.sum-(t.r==lastx);
lastx=t.l;
x=fa[top[x]];
}
else{
ret t=query(1,n,1,ttol[top[y]],ttol[y]);
res+=t.sum-(t.r==lasty);
lasty=t.l;
y=fa[top[y]];
}
}
res-=(lastx==query(1,n,1,ttol[x],ttol[x]).l)+(lasty==query(1,n,1,ttol[y],ttol[y]).l);
if(dep[x]>dep[y])swap(x,y);
res+=query(1,n,1,ttol[x],ttol[y]).sum;
return res;
}
signed main(){
n=in,m=in;
for(int i=1;i<=n;i++)
w[i]=in;
for(int i=1;i<n;i++){
int u=in,v=in;
insert(u,v);
insert(v,u);
}
dfs1(1,0);
dfs2(1,1);
built(1,n,1);
for(int i=1;i<=m;i++){
char c[5];
cin>>c;
if(c[0]=='C'){
int a=in,b=in,c=in;
changeit(a,b,c);
}
else{
int a=in,b=in;
cout<<queryit(a,b)<<'\n';
}
}
return 0;
}
题外话:
虽然一遍过了,但我还是不想再看到类似的题了。
标签:颜色,洛谷,int,res,top,ttol,SDOI2011,query,P2486 来源: https://www.cnblogs.com/llmmkk/p/15185582.html