• BZOJ2152


    Portal

    Description

    给出一个(n(nleq2 imes10^4))个点的带边权树,随机从中选择两个点(u,v)(可以相同),求路径((u,v))的长度恰为(3)的倍数的概率。

    Solution

    点分治。
    统计过根的答案时,依然使用容斥原理。记点(u)到根(rt)的距离为(dst[u])calc(u)表示以(u)为根的子树中有多少有序点对((v_1,v_2))满足(dst[v_1]+dst[v_2])(3)的倍数,那么过根的长度为(3)的倍数的路径条数就等于(calc(rt)-sum_{uin son_{rt}}calc(u))。与上一题很相似呢。

    时间复杂度(O(nlogn))

    Code

    //聪聪可可
    #include <algorithm>
    #include <cstdio>
    using std::max;
    typedef long long lint;
    inline char gc()
    {
    	static char now[1<<16],*s,*t;
    	if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
    	return *s++;
    }
    inline int read()
    {
    	int x=0; char ch=gc();
    	while(ch<'0'||'9'<ch) ch=gc();
    	while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    	return x;
    }
    int const N=2e4+10;
    int n;
    int h[N],cnt;
    struct edge{int v,w,nxt;} ed[N<<1];
    void edAdd(int u,int v,int w)
    {
    	cnt++; ed[cnt].v=v,ed[cnt].w=w,ed[cnt].nxt=h[u],h[u]=cnt;
    	cnt++; ed[cnt].v=u,ed[cnt].w=w,ed[cnt].nxt=h[v],h[v]=cnt;
    }
    lint ans1,ans2;
    int G,siz0,siz[N],chSiz[N]; bool vst[N];
    void getG(int u,int fa)
    {
    	siz[u]=1,chSiz[u]=0;
    	for(int i=h[u];i;i=ed[i].nxt)
    	{
    		int v=ed[i].v;
    		if(vst[v]||v==fa) continue;
    		getG(v,u); siz[u]+=siz[v],chSiz[u]=max(chSiz[u],siz[v]);
    	}
    	chSiz[u]=max(chSiz[u],siz0-siz[u]);
    	if(chSiz[u]<chSiz[G]) G=u;
    }
    lint cur[5];
    void getCur(int u,int fa,int d)
    {
    	cur[d]++;
    	for(int i=h[u];i;i=ed[i].nxt)
    	{
    		int v=ed[i].v;
    		if(vst[v]||v==fa) continue;
    		getCur(v,u,(d+ed[i].w)%3);
    	}
    }
    lint calc(int u,int d0)
    {
    	cur[0]=cur[1]=cur[2]=0; getCur(u,0,d0%3);
    	lint res=cur[0]*cur[0]+cur[1]*cur[2]+cur[2]*cur[1];
    	return res;
    }
    void solve(int u);
    void DC(int u)
    {
    	siz[u]=siz0; vst[u]=true; ans1+=calc(u,0);
    	for(int i=h[u];i;i=ed[i].nxt)
    	{
    		int v=ed[i].v;
    		if(vst[v]) continue;
    		if(siz[v]>siz[u]) siz[v]=siz0-siz[u];
    		ans1-=calc(v,ed[i].w);
    	}
    	for(int i=h[u];i;i=ed[i].nxt) {int v=ed[i].v; if(!vst[v]) solve(v);}
    }
    void solve(int u) {siz0=siz[u],G=0,chSiz[G]=n,getG(u,0),DC(G);}
    lint gcd(lint x,lint y) {return (x%y)?gcd(y,x%y):y;}
    int main()
    {
    	n=read();
    	for(int i=1;i<=n-1;i++)
    	{
    		int u=read(),v=read(),w=read();
    		edAdd(u,v,w);
    	}
    	ans1=0; siz[1]=n,solve(1);
    	ans2=(lint)n*n;
    	lint g=gcd(ans1,ans2);
    	printf("%lld/%lld
    ",ans1/g,ans2/g);
    	return 0;
    }
    
    
  • 相关阅读:
    老罗锤子手机发布会,我感到深深地愧疚!
    微价值:专访《甜心爱消除》的个人开发者Lee,日入千元
    [个人开发者赚钱二]从自己最熟悉的方面入手,获取小利
    [个人开发者赚钱一]改变思维,从心开始
    个人开发者赚钱一、改变思维,从心开始
    OC中的点语法,成员变量的作用域
    OC self super isa指针
    OC面向对象多态笔记
    OC面向对象继承关系和组合关系笔记
    OC面向对象封装
  • 原文地址:https://www.cnblogs.com/VisJiao/p/BZOJ2152.html
Copyright © 2020-2023  润新知