• #线段树合并#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);
    }
    
  • 相关阅读:
    在mac下使用ppk文件ssh到远程主机
    Openstack镜像和密码
    ubuntu下如何用命令行运行deb安装包
    python中使用@property
    linux里的vi怎么移动到最后一行
    Git 怎样保证fork出来的project和原project(上游项目)同步更新
    使用msgfmt编译多语言文件
    ubuntu创建文件夹快捷方式命令
    ssh: connect to host localhost port 22: Connection refused 问题
    excel中如何批量将所有的网址设为超链接
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13916736.html
Copyright © 2020-2023  润新知