【LOJ #2386】「USACO 2018.01 Platinum」Cow at Large(点分治 / 树状数组)

传送门

不知道为什么 l g lg 题解里清一色只会用 d = 2 m 1 1 = 2 m d \sum d=2m-1\rightarrow 1=2m-\sum d 容斥做法

m n l e a f u \mathit{mnleaf_u} 表示距点 u u 最近的叶子节点的距离
这个可以用脚 d f s dfs 随便 O ( n / n l o g n ) O(n/nlogn)
对于一个根的情况就是统计
u [ m n l e a f u d e p u   & &   m n l e a f f a [ u ] d e p u ] \sum_{u}[\mathit{mnleaf_u}\le dep_u\ \&\&\ \mathit{mnleaf_{fa[u]}}\geq dep_u]

对于所有点询问,考虑点分治
那么一个子树中 u u 对另一个子树中的 v v 的贡献就是
[ m n l e a f u d e p u + d e p v   & &   m n l e a f f a [ u ] d e p u + d e p v ] [\mathit{mnleaf_u}\le dep_u+dep_v\ \&\&\ \mathit{mnleaf_{fa[u]}}\geq dep_u+dep_v]

移一下项就是 u u 区间加, v v 单点求值
于是点分即可
先把整个 d f s dfs 然后枚举求值的子树减去这个子树自己的贡献然后随便算算即可
注意记得把当前分治中心的贡献加进去
就是往哪个子树求值就把中心的父亲设为哪个

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?res:-res;
}
template<typename tp>inline void chemx(tp &a,tp b){a=max(a,b);}
template<typename tp>inline void chemn(tp &a,tp b){a=min(a,b);}
cs int N=70005;
int n,mnleaf[N],isleaf[N];
vector<int> e[N];
void dfs(int u,int fa){mnleaf[u]=1e9;int fg=0;
	for(int &v:e[u])if(v!=fa){
		fg=1;dfs(v,u);
		chemn(mnleaf[u],mnleaf[v]+1);
	}
	if(!fg||(u==1&&e[u].size()==1))mnleaf[u]=0,isleaf[u]=1;
}
void dfs1(int u,int tp,int fa){
	chemn(mnleaf[u],tp);
	multiset<int>st;st.insert(mnleaf[u]);
	for(int &v:e[u])if(v!=fa){
		st.insert(mnleaf[v]+1);
	}
	for(int &v:e[u])if(v!=fa){
		st.erase(st.find(mnleaf[v]+1));
		int vl=mnleaf[v]+1;
		dfs1(v,min(tp,*st.bg())+1,u);
		st.insert(vl);
	}
}
namespace bit{
	int tr[2*N],stk[N*6],top;
	#define lb(x) (x&(-x))
	void write(){
		for(int i=1;i<=n+n;i++)cout<<tr[i]<<" ";puts("");
	}
	void upd(int p,int k){stk[++top]=p;
		for(;p<=n+n;p+=lb(p))tr[p]+=k;
	}
	void delet(int p){
		for(;p<=n+n;p+=lb(p))tr[p]=0;
	}
	void clear(){
		while(top)delet(stk[top--]);
	}
	void update(int l,int r,int k){
		if(l>r)return;l+=n,r+=n;
		upd(l,k),upd(r+1,-k);
	}
	int query(int p,int res=0){p+=n;
		for(;p>0;p-=lb(p))res+=tr[p];return res;
	}
	#undef lb
};
int maxn,mxsiz,rt;
int siz[N],vis[N],fa[N],dep[N],ans[N];
void getrt(int u,int fa){
	siz[u]=1;int son=0;
	for(int v:e[u])if(!vis[v]&&v!=fa){
		getrt(v,u),siz[u]+=siz[v];
		chemx(son,siz[v]);
	}chemx(son,maxn-siz[u]);
	if(son<mxsiz)mxsiz=son,rt=u;
}
vector<int>nd[N];
void dfs2(int u,int root){
	nd[root].pb(u),bit::update(mnleaf[u]-dep[u],mnleaf[fa[u]]-dep[u],1);
	for(int v:e[u])if(!vis[v]&&v!=fa[u])fa[v]=u,dep[v]=dep[u]+1,dfs2(v,root);
}
void delet(int u){
	for(int &v:nd[u])
	bit::update(mnleaf[v]-dep[v],mnleaf[fa[v]]-dep[v],-1);
}
void insert(int u){
	for(int &v:nd[u])
	bit::update(mnleaf[v]-dep[v],mnleaf[fa[v]]-dep[v],1);	
	nd[u].resize(0);
}
void getans(int u){
	ans[u]+=bit::query(dep[u]);
	for(int v:e[u])if(!vis[v]&&v!=fa[u])getans(v);
}
void solve(int u){
	vis[u]=1;
	for(cs int &v:e[u])if(!vis[v]){
		fa[v]=u,dep[v]=1,dfs2(v,v);
	}
	ans[u]+=bit::query(0);
	for(cs int &v:e[u])if(!vis[v]){
		delet(v);
		bit::update(mnleaf[u],mnleaf[v],1);
		getans(v);
		bit::update(mnleaf[u],mnleaf[v],-1);
		insert(v);
	}
	bit::clear();
	for(cs int &v:e[u])if(!vis[v]){
		maxn=siz[v],mxsiz=1e9,getrt(v,u);
		solve(rt);
	}
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read();maxn=n;mxsiz=1e9;
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		e[u].pb(v),e[v].pb(u);
	}dfs(1,0);
	dfs1(1,1e9,0);
	getrt(1,0);
	solve(rt);
	for(int i=1;i<=n;i++)if(!isleaf[i])cout<<ans[i]<<'\n';else cout<<1<<'\n';
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/105778238
今日推荐