[SDOI2011]染色 (线段树维护子段问题+树剖)
Posted 昵称很长很长真是太好了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2011]染色 (线段树维护子段问题+树剖)相关的知识,希望对你有一定的参考价值。
题意:
给定一棵 n 个节点的无根树,共有 m 个操作,操作分为两种:
1.将节点 a 到节点 b 的路径上的所有点(包括 a 和 b)都染成颜色 c。
2.询问节点 a 到节点 b 的路径上的颜色段数量。
颜色段的定义是极长的连续相同颜色被认为是一段。例如 112221 由三段组成:11、222、1。
题解:
树剖+线段树维护区间子段和问题。
如果在在单独的线段树上操作的话,难度还不是特别高,这个题因为转移到了树上去,树剖的本质是把线段树的区间给分成了好几段,所以我们在经过树上路径的时候,衔接位置要特别注意。
一个小细节的地方。!!!
由代码可见,这是两种不同的写法;
出锅的原因:未考虑清楚L1由x决定,那么L2应由x匹配,L2则与y;
if(dep[x]<dep[y])
swap(x,y),swap(ansl,ansr);
ans+=query(1,id[y],id[x],id[y],id[x]);
if(Rc==ansl) ans--;
if(Lc==ansr) ans--;
/*
if(dep[x]>dep[y])
swap(x,y),swap(ansl,ansr);
ans+=query(1,id[x],id[y],id[x],id[y]);
if(Lc==ansl) ans--;
if(Rc==ansr) ans--;*/
代码:
//#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
//#define int long long
const int maxn=1e5+10;
#define endl '\\n'
struct node{
int to,next;
}edge[maxn*2];
int a[maxn],head[maxn*2],dep[maxn];
int f[maxn],sz[maxn],son[maxn];
int tot;int n,m;
void add(int u,int v){
edge[tot].to=v,edge[tot].next=head[u];
head[u]=tot++;
edge[tot].to=u,edge[tot].next=head[v];
head[v]=tot++;
}
void dfs1(int x,int fa){
f[x]=fa;
dep[x]=dep[fa]+1;
sz[x]=1;
for(int i=head[x];~i;i=edge[i].next){
int to=edge[i].to;
if(to==fa) continue;
dfs1(to,x);
sz[x]+=sz[to];
if(sz[to]>sz[son[x]]) son[x]=to;
}
}
int dfn[maxn],top[maxn],w[maxn];
int cnt;
void dfs2(int x,int t){
dfn[x]=++cnt;
top[x]=t;
w[cnt]=a[x];
if(!son[x]) return ;
dfs2(son[x],t);
for(int i=head[x];~i;i=edge[i].next){
int to=edge[i].to;
if(to==f[x]||to==son[x]) continue;
dfs2(to,to);
}
}
int lcol[maxn*4],rcol[maxn*4],tree[maxn*4];
void push_up(int node){
if(rcol[node*2]==lcol[node*2+1]){
tree[node]=tree[node*2]+tree[node*2+1]-1;
}
else tree[node]=tree[node*2]+tree[node*2+1];
lcol[node]=lcol[node*2];
rcol[node]=rcol[node*2+1];
}
void build(int node,int start,int ends){
if(start==ends){
tree[node]=1;
lcol[node]=rcol[node]=w[start];
return ;
}
int mid=(start+ends)/2;
build(node*2,start,mid);
build(node*2+1,mid+1,ends);
push_up(node);
}
int lazy[maxn*4];
void push_down(int node){
if(lazy[node]!=0){
lazy[node*2]=lazy[node*2+1]=lazy[node];
lcol[node*2]=rcol[node*2]=lcol[node*2+1]=rcol[node*2+1]=lazy[node];
tree[node*2]=tree[node*2+1]=1;
lazy[node]=0;
}
}
void update(int node,int start,int ends,int l,int r,int val){
if(l<=start&&ends<=r){
tree[node]=1;
lcol[node]=rcol[node]=lazy[node]=val;
return ;
}
int mid=(start+ends)/2;
push_down(node);
if(l<=mid) update(node*2,start,mid,l,r,val);
if(mid<r) update(node*2+1,mid+1,ends,l,r,val);
push_up(node);
}
int querycnt(int node,int start,int ends,int l,int r,int &ansl,int &ansr){
if(l<=start&&ends<=r){
if(l==start) ansl=lcol[node];
if(r==ends) ansr=rcol[node];
return tree[node];
}
int mid=(start+ends)/2;
push_down(node);
int res=0;
if(l<=mid) res+=querycnt(node*2,start,mid,l,r,ansl,ansr);
if(mid<r) res+=querycnt(node*2+1,mid+1,ends,l,r,ansl,ansr);
if(rcol[node*2]==lcol[node*2+1]&&l<=mid&&mid<r) return res-1;
else return res;
}
//int querycol(int node,int start,int ends,int pos){
// if(start==ends) return lcol[node];
// int mid=(start+ends)/2;
// push_down(node);
// if(pos<=start) return querycol(node*2,start,mid,pos);
// else return querycol(node*2+1,mid+1,ends,pos);
//}
void upchain(int x,int y,int val){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,dfn[top[x]],dfn[x],val);
x=f[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,1,n,dfn[x],dfn[y],val);
}
int querychain(int x,int y){
int res=0;
int L1=-1,L2=-1,Lc,Rc;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]){
swap(x,y);
swap(L1,L2);
}
res+=querycnt(1,1,n,dfn[top[x]],dfn[x],Lc,Rc);
// cout<<" l "<<dfn[top[x]]<<" r "<<dfn[x]<<endl;
// cout<<"debug "<<res<<endl;
if(L1==Rc) res--;
L1=Lc;x=f[top[x]];
}
if(dep[x]<dep[y]){
swap(x,y);swap(L1,L2);
}
res+=querycnt(1 ,1,n,dfn[y],dfn[x],Lc,Rc);
if(Rc==L1) res--;
if(Lc==L2) res--;
return res;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(head,-1,sizeof head);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
add(x,y);
}
dfs1(1,1);
dfs2(1,1);
build(1,1,n);
// for(int i=1;i<=n;i++){
// cout<<"dfn "<<i<<" "<<top[i]<<endl;
// }
for(int i=1;i<=m;i++){
char opt;
cin>>opt;
if(opt=='C'){
int x,y,z;
cin>>x>>y>>z;
upchain(x,y,z);
}
else{
int x,y;
cin>>x>>y;
cout<<querychain(x,y)<<endl;
}
}
}
以上是关于[SDOI2011]染色 (线段树维护子段问题+树剖)的主要内容,如果未能解决你的问题,请参考以下文章