您的位置:首页 > 其它

bzoj4817 [Sdoi2017]树点涂色

2017-04-12 10:29 513 查看

传送门

吐槽一波怎么今年的山东OI这么水……(装B

不难看出第一种操作就是LCT的access,那么每个点到根节点的颜色种数就是虚边数量+1,两点间颜色种数同理……

第三种操作可以用把每个虚边挂着的点的子树权值全部+1的方式来维护,那么直接LCT+区间修改区间求max的线段树维护即可,复杂度$O(n\log^2 n)$。

/**************************************************************
Problem: 4817
User: _Angel_
Language: C++
Result: Accepted
Time:5500 ms
Memory:21092 kb
****************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define isroot(x) ((x)->p==null||((x)!=(x)->p->ch[0]&&(x)!=(x)->p->ch[1]))
#define dir(x) ((x)==(x)->p->ch[1])
using namespace std;
const int maxn=100010;
struct node{node *ch[2],*p;}null[maxn];
void dfs(int);
int LCA(int,int);
node *access(node*);
node *getroot(node*);
void splay(node*);
void rot(node*,int);
void modify(int,int,int);
int query(int,int,int);
int mx[maxn<<2]={0},lazy[maxn<<2]={0};
vector<int>G[maxn];
int f[maxn][20],d[maxn],dfn[maxn],finish[maxn],tim=0;
int n,m,lgn=0,s,t,k,x,y;
int main(){
null->ch[0]=null->ch[1]=null->p=null;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)null[i].ch[0]=null[i].ch[1]=null[i].p=null;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1);
for(int j=1;j<=lgn;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
while(m--){
scanf("%d%d",&k,&x);
if(k==1)access(null+x);
else if(k==2){
scanf("%d",&y);
s=t=dfn[x];
int ans=query(1,n,1);
s=t=dfn[y];
ans+=query(1,n,1);
s=t=dfn[LCA(x,y)];
ans-=query(1,n,1)<<1;
printf("%d\n",ans+1);
}
else if(k==3){
s=dfn[x];
t=finish[x];
printf("%d\n",query(1,n,1)+1);
}
}
return 0;
}
void dfs(int x){
dfn[x]=++tim;
d[x]=d[f[x][0]]+1;
null[x].p=null+f[x][0];
while((1<<lgn)<d[x])lgn++;
for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=f[x][0]){
f[G[x][i]][0]=x;
dfs(G[x][i]);
}
finish[x]=tim;
if(f[x][0]){
s=dfn[x];
t=finish[x];
k=1;
modify(1,n,1);
}
}
int LCA(int x,int y){
if(d[x]!=d[y]){
if(d[x]<d[y])swap(x,y);
for(int i=lgn;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
}
if(x==y)return x;
for(int i=lgn;i>=0;i--)if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
return f[x][0];
}
node *access(node *x){
node *y=null;
while(x!=null){
splay(x);
if(x->ch[1]!=null){
node *u=x->ch[1];
x->ch[1]=null;
u=getroot(u);
s=dfn[u-null];
t=finish[u-null];
k=1;
modify(1,n,1);
}
if(y!=null){
y=getroot(y);
s=dfn[y-null];
t=finish[y-null];
k=-1;
modify(1,n,1);
}
x->ch[1]=y;
y=x;
x=x->p;
}
return y;
}
node *getroot(node *x){
splay(x);
while(x->ch[0]!=null)x=x->ch[0];
splay(x);
return x;
}
void splay(node *x){
while(!isroot(x)){
if(isroot(x->p)){
rot(x->p,dir(x)^1);
break;
}
if(dir(x)==dir(x->p))rot(x->p->p,dir(x->p)^1);
else rot(x->p,dir(x)^1);
rot(x->p,dir(x)^1);
}
}
inline void rot(node *x,int d){
node *y=x->ch[d^1];
if((x->ch[d^1]=y->ch[d])!=null)y->ch[d]->p=x;
y->p=x->p;
if(!isroot(x))x->p->ch[dir(x)]=y;
(y->ch[d]=x)->p=y;
}
void modify(int l,int r,int rt){
if(s<=l&&t>=r){
mx[rt]+=k;
lazy[rt]+=k;
return;
}
int mid=(l+r)>>1;
if(s<=mid)modify(l,mid,rt<<1);
if(t>mid)modify(mid+1,r,rt<<1|1);
mx[rt]=max(mx[rt<<1],mx[rt<<1|1])+lazy[rt];
}
int query(int l,int r,int rt){
if(s<=l&&t>=r)return mx[rt];
int mid=(l+r)>>1,ans=0;
if(s<=mid)ans=max(ans,query(l,mid,rt<<1));
if(t>mid)ans=max(ans,query(mid+1,r,rt<<1|1));
return ans+lazy[rt];
}
View Code

ps:如果没记错的话,这题应该是重组病毒那题的超级弱化版……

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: