cf768g The Winds Of Winter

传送门
调了半天,是读优里面异或忘记打括号了。
维护三种平衡树:
①全局平衡树(不包含根到当前节点的链)
②路径平衡树(包含从根到当前点的路径上的点,除了根节点。因为根节点没有父亲节点)
③每个节点维护一个子树中存在的子树 s i z siz siz的平衡树
然后删掉一个点后,形成的森林里面的 s i z siz siz值有一个 m x mx mx m n mn mn s u b m x submx submx(次大), m x mx mx对应一个 m x s o n mxson mxson
首先二分的答案 x x x一定大等于 s u b m x submx submx,因为只能移动一个。
令移动的子树大小为 d e l t a delta delta,那么有:
x ≥ m x − d e l t a , x ≥ m n + d e l t a ⇒ m x − x ≤ d e l t a ≤ x − m n x \geq mx-delta,x \geq mn+delta \Rightarrow mx-x \le delta \le x-mn xmxdelta,xmn+deltamxxdeltaxmn
于是在区间里面找是否存在这样一个 d e l t a delta delta即可。

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using namespace std;
cs int N=1e5+10;
int n,u,f,root,rt_all,rt_path,rt[N],fa[N],ans[N];
inline int read(){
	int x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
	return x;
}
namespace SBT{
	cs double alpha=0.55;
	cs int M=N<<2|1;
	int lc[M],rc[M],tot;
	int val[M],c[M],siz[M],rsiz[M];
	int dl[M],tp,q[M],qc[M],qn;
	inline int newnode(int v,int ct){
		int u=tp?dl[tp--]:++tot;
		lc[u]=rc[u]=0,val[u]=v,c[u]=siz[u]=ct,rsiz[u]=1;
		return u;
	}
	inline void pushup(int u){
		rsiz[u]=rsiz[lc[u]]+rsiz[rc[u]]+1;
		siz[u]=siz[lc[u]]+siz[rc[u]]+c[u];
	}
	inline void Zig(int &u){
		int v=lc[u];lc[u]=rc[v],rc[v]=u;
		pushup(u),pushup(v);u=v;
	}
	inline void Zag(int &u){
		int v=rc[u];rc[u]=lc[v],lc[v]=u;
		pushup(u),pushup(v);u=v;
	}
	inline void ins(int &u,int v,int ct=1){
		if(!u){u=newnode(v,ct);return;}
		siz[u]+=ct;
		if(val[u]==v) c[u]+=ct;
		else if(v<val[u]){
			ins(lc[u],v,ct);
			if(rsiz[lc[u]]>rsiz[u]*alpha) Zig(u);
		}
		else{
			ins(rc[u],v,ct);
			if(rsiz[rc[u]]>rsiz[u]*alpha) Zag(u);
		}pushup(u);
	}
	inline void del(int &u,int v){
		if(!u) return;
		if(val[u]==v){
			if(c[u]>1) --c[u],--siz[u];
			else if(!lc[u]||!rc[u]) dl[++tp]=u,u=lc[u]|rc[u];
			else if(rsiz[lc[u]]<rsiz[rc[u]]) Zag(u),del(u,v);
			else Zig(u),del(u,v);
			if(u) pushup(u);
			return;
		}
		if(v<val[u]) del(lc[u],v);
		else del(rc[u],v);
		pushup(u);
	}
	inline int Rank(int u,int v,int ans=0){
		while(u){
			if(val[u]==v) return ans+siz[lc[u]]+c[u];
			if(val[u]<v) ans+=siz[lc[u]]+c[u],u=rc[u];
			else u=lc[u];
		}return ans;
	}
	inline int range(int rt,int l,int r){return Rank(rt,r)-Rank(rt,l-1);}
	void inorder_dfs(int u){
		if(lc[u]) inorder_dfs(lc[u]);
		q[++qn]=val[u],qc[qn]=c[u],dl[++tp]=u;
		if(rc[u]) inorder_dfs(rc[u]);
	}
	inline void Join(int &u,int &v){
		if(rsiz[u]<rsiz[v]) std::swap(u,v);
		qn=0,inorder_dfs(v),v=0;
		for(int re i=1;i<=qn;++i) ins(u,q[i],qc[i]);
	}
}
using SBT::ins;
using SBT::del;
using SBT::range;
using SBT::Join;
namespace GRAPH{
	int Head[N],Next[N<<1],V[N<<1],siz[N],cnt=0;
	inline void add(int u,int v){Next[++cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
	void pre_dfs(int u){
		siz[u]=1;
		for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
			if(v!=fa[u]) pre_dfs(v),siz[u]+=siz[v];
	}
	inline bool check(int u,int mxson,int mn,int mx,int lim){
		int l=mx-lim,r=lim-mn;
		if(l>r) return false;
		if(mxson==fa[u]) return (range(rt_all,l,r)-range(rt[u],l,r)+range(rt_path,l+siz[u],r+siz[u]))>0;
		else return range(rt[mxson],l,r)>0;
	}
	void solve(int u){
		del(rt_all,siz[u]);
		if(u!=root) ins(rt_path,siz[u]);
		int mn=n+1,mx=0,submx=0,mxson=0;
		for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]]){
			int siz_v=v==fa[u]?n-siz[u]:siz[v];
			if(v!=fa[u]) solve(v);mn=min(mn,siz_v);
			if(siz_v>mx) submx=mx,mxson=v,mx=siz_v;
			else if(siz_v>submx)submx=siz_v;
		}
		ins(rt_all,siz[u]),ins(rt[u],siz[u]);
		if(u!=root) del(rt_path,siz[u]);
		if(mxson==fa[u]) for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
			if(v!=fa[u]) Join(rt[u],rt[v]);
		int l=submx==0?mx:submx,r=mx,mid;
		while(l<r) check(u,mxson,mn,mx,mid=l+r>>1)?r=mid:l=mid+1;ans[u]=l;
		if(mxson!=fa[u]) for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
			if(v!=fa[u]) Join(rt[u],rt[v]);
	}
}
using GRAPH::add;
int main(){
	n=read();
	for(int re i=1;i<=n;++i){
		f=read(),u=read();
		if(!f) root=u;
		else add(fa[u]=f,u),add(u,f);
	}GRAPH::pre_dfs(root);
	for(int re i=1;i<=n;++i) ins(rt_all,GRAPH::siz[i]);
	GRAPH::solve(root);
	for(int re i=1;i<=n;++i) printf("%d\n",ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值