您的位置:首页 > 其它

bzoj4817: [Sdoi2017]树点涂色

2017-04-12 09:19 423 查看

Description

Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x y:
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作

Input

第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000

Output

每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值
由于染色都是从根开始的一条路径,可以发现:
操作1就是无换根操作的lct的access,操作2是查询给定路径经过lct中几条虚边,操作3是查询子树内到根的最大虚边条数
lct每次access均摊修改O(logn)条边的虚实,因此可以维护原树的lct方便操作1
树链剖分+树状数组维护路径上虚边条数
线段树维护dfs序,区间内点到根路径上最大虚边条数
于是每次修改边的类型时,对应在树状数组上单点修改,线段树上区间加
总复杂度O(mlog2(n))

#include<cstdio>
const int N=100007;
char buf[N*100],*ptr=buf-1;
int _(){
int x=0,c=*++ptr;
while(c<48)c=*++ptr;
while(c>47)x=x*10+c-48,c=*++ptr;
return x;
}
int n,m,es[N*2],enx[N*2],e0
,ep=2,dw
;
int _l,_r,_a;
int max(int a,int b){return a>b?a:b;}
namespace SGT{
struct node{
node*lc,*rc;
int L,R,M;
int mx,a;
void _add(int x){
mx+=x;a+=x;
}
void dn(){
if(a){
lc->_add(a);
rc->_add(a);
a=0;
}
}
void up(){
mx=max(lc->mx,rc->mx);
}
void add(){
if(_l<=L&&R<=_r){
_add(_a);
return;
}
dn();
if(_l<=M)lc->add();
if(_r>M)rc->add();
up();
}
int gmx(){
if(_l<=L&&R<=_r)return mx;
dn();
if(_r<=M)return lc->gmx();
if(_l>M)return rc->gmx();
return max(lc->gmx(),rc->gmx());
}
}ns[N*2],*np=ns,*rt;
node*build(int L,int R){
node*w=np++;
w->L=L;w->R=R;
if(L<R){
int M=w->M=L+R>>1;
w->lc=build(L,M);
w->rc=build(M+1,R);
}
return w;
}
}
namespace BIT{
int f
;
void inc(int w,int x){
for(;w<=n;w+=w&-w)f[w]+=x;
}
int sum(int w){
int s=0;
for(;w;w-=w&-w)s+=f[w];
return s;
}
}
namespace HLD{
using namespace SGT;
using namespace BIT;
int fa
,sz
,son
,dep
,top
,id
,id2
,idp=0;
void f1(int w,int pa){
dep[w]=dep[fa[w]=pa]+1;
sz[w]=1;
for(int i=e0[w];i;i=enx[i]){
int u=es[i];
if(u!=pa){
f1(u,w);
sz[w]+=sz[u];
if(sz[u]>sz[son[w]])son[w]=u;
}
}
}
void f2(int w,int tp){
top[w]=tp;
id[w]=++idp;
if(son[w])f2(son[w],tp);
for(int i=e0[w];i;i=enx[i]){
int u=es[i];
if(u!=fa[w]&&u!=son[w])f2(u,u);
}
id2[w]=idp;
}
int lca(int x,int y){
int a=top[x],b=top[y],s=1;
while(a!=b){
if(dep[a]>dep[b]){
s+=BIT::sum(id[x])-BIT::sum(id[a]-1);
x=fa[a],a=top[x];
}else{
s+=BIT::sum(id[y])-BIT::sum(id[b]-1);
y=fa[b],b=top[y];
}
}
if(dep[x]>dep[y])s+=BIT::sum(id[x])-BIT::sum(id[y]);
if(dep[x]<dep[y])s+=BIT::sum(id[y])-BIT::sum(id[x]);
return s;
}
void init(){
f1(1,0);f2(1,1);
rt=build(1,n);
for(int i=2;i<=n;++i){
inc(id[i],1);
_l=id[i],_r=id2[i],_a=1;
rt->add();
}
}
int query(int x){
_l=id[x],_r=id2[x];
return rt->gmx()+1;
}
void setdw(int x,int y){
if(dw[x]){
inc(id[dw[x]],1);
_l=id[dw[x]],_r=id2[dw[x]],_a=1;
rt->add();
}
if(dw[x]=y){
inc(id[y],-1);
_l=id[y],_r=id2[y],_a=-1;
rt->add();
}
}
}
namespace LCT{
#define lc ch][0
#define rc ch][1
#define fa ch][2
int ch
[4];
bool nrt(int x){return x==x[fa][lc]||x==x[fa][rc];}
void rot(int x){
int f=x[fa],g=f[fa],d=(x!=f[lc]);
if(nrt(f))g[ch][g[lc]!=f]=x;
x[fa]=g;
(f[ch][d]=x[ch][d^1])[fa]=f;
(x[ch][d^1]=f)[fa]=x;
}
void sp(int x){
while(nrt(x)){
int f=x[fa];
if(nrt(f))rot((x==f[lc])==(f==f[fa][lc])?f:x);
rot(x);
}
}
int gl(int x){
while(x[lc])x=x[lc];
sp(x);
return x;
}
void acs(int x){
for(int y=0;x;sp(x),HLD::setdw(x,y),x[rc]=y,y=gl(x),x=y[fa]);
}
#undef lc
#undef rc
#undef fa
}
int main(){
fread(buf,1,sizeof(buf),stdin)[buf]=0;
n=_();m=_();
for(int i=1,a,b;i<n;++i){
a=_();b=_();
es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
}
HLD::init();
for(int i=2;i<=n;++i)LCT::ch[i][2]=HLD::fa[i];
for(int i=0,o,a,b;i<m;++i){
o=_();
if(o==1){
a=_();
LCT::acs(a);
}else if(o==2){
a=_();b=_();
printf("%d\n",HLD::lca(a,b));
}else{
a=_();
printf("%d\n",HLD::query(a));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: