#线段树合并#JZOJ 5365 通信

BrUW3F.png


分析

取出一段区间后答案就是虚树边的个数的两倍,
考虑计算\(x\)与父亲的边对答案的贡献,
那么不能够贡献的就是\(x\)的子树下标连续的一段或者是非\(x\)的子树连续的一段,
考虑将\(x\)的子树染色,然后线段树合并


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int mod=1000000007,N=100011;
struct node{int y,next;}e[N<<1];
int n,et=1,ans,m,rt[N],as[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed C(int n){return (1ll*n*(n+1)/2)%mod;}
inline signed ksm(int x,int y){
	rr int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans;
}
inline signed mo1(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline signed mo2(int x,int y){return x<y?x-y+mod:x-y;}
struct Segment_Tree{
	int Ls[N*20],Rs[N*20],lw[N*20],rw[N*20],lb[N*20],rb[N*20],w[N*20],tot;
	inline void pup(int k,int l,int r){
		rr int ls=Ls[k],rs=Rs[k],mid=(l+r)>>1;
		if (!ls) ls=++tot,lw[ls]=rw[ls]=0,w[ls]=C(lb[ls]=rb[ls]=mid-l+1);
		if (!rs) rs=++tot,lw[rs]=rw[rs]=0,w[rs]=C(lb[rs]=rb[rs]=r-mid);
		w[k]=mo1(w[ls],w[rs]);
		if (rw[ls]&&lw[rs]) w[k]=mo1(w[k],mo2(C(rw[ls]+lw[rs]),mo1(C(rw[ls]),C(lw[rs]))));
		if (rb[ls]&&lb[rs]) w[k]=mo1(w[k],mo2(C(rb[ls]+lb[rs]),mo1(C(rb[ls]),C(lb[rs]))));
		lw[k]=lw[ls]+((lw[ls]==mid-l+1)?lw[rs]:0),
		rw[k]=rw[rs]+((rw[rs]==r-mid)?rw[ls]:0),
		lb[k]=lb[ls]+((lb[ls]==mid-l+1)?lb[rs]:0),
		rb[k]=rb[rs]+((rb[rs]==r-mid)?rb[ls]:0);
	}
	inline signed update(int rt,int l,int r,int x){
		if (!rt) rt=++tot;
		if (l==r){
			w[rt]=lw[rt]=rw[rt]=1,
			lb[rt]=rb[rt]=0;
			return rt; 
		}
		rr int mid=(l+r)>>1;
		if (x<=mid) Ls[rt]=update(Ls[rt],l,mid,x);
		    else Rs[rt]=update(Rs[rt],mid+1,r,x);
		pup(rt,l,r);
		return rt;
	}
	inline signed Merge(int fi,int se,int l,int r){
		if (!fi||!se) return fi|se;
		if (lb[fi]==r-l+1) return se;
		if (rb[se]==r-l+1) return fi;
		rr int mid=(l+r)>>1;
		Ls[fi]=Merge(Ls[fi],Ls[se],l,mid);
		Rs[fi]=Merge(Rs[fi],Rs[se],mid+1,r);
		pup(fi,l,r);
		return fi;
	}
}Tre;
inline void dfs(int x,int fa){
	for (rr int i=as[x];i;i=e[i].next) if (e[i].y!=fa)
	    dfs(e[i].y,x),rt[x]=Tre.Merge(rt[x],rt[e[i].y],1,n);
	rt[x]=Tre.update(rt[x],1,n,x),ans=mo1(ans,mo2(m,Tre.w[rt[x]]));
}
signed main(){
	freopen("communicate.in","r",stdin);
	freopen("communicate.out","w",stdout);
	n=iut(),Tre.tot=0,m=C(n);
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut();
		e[++et]=(node){y,as[x]},as[x]=et;
		e[++et]=(node){x,as[y]},as[y]=et;
	}
	dfs(1,0);
	ans=2ll*ans*ksm(m,mod-2)%mod;
	return !printf("%d",ans);
}
posted @ 2020-11-02 21:48  lemondinosaur  阅读(57)  评论(0编辑  收藏  举报