通信

来源:互联网 发布:vm安装mac os 编辑:程序博客网 时间:2024/05/02 00:52

题目大意

在树上随机选一个序号区间的点,求构成的虚树大小期望(类似这个意思,其实是2*虚树大小-2)

做法

可以想到枚举区间右端点,每个节点记录cnt表示存在多少k使得[k,i]构成虚树包含自己(i是当前右端),然后每次统计答案与修改cnt复杂度与树高有关。
这个暴力可以树剖优化,但数据随机所以暴力跑过去了。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=100000+10,mo=1000000007;int h[maxn],go[maxn*2],nxt[maxn*2],num[maxn],dep[maxn],father[maxn];int i,j,k,l,r,t,n,m,tot,ans,now;int qsm(int x,int y){    if (!y) return 1;    int t=qsm(x,y/2);    t=(ll)t*t%mo;    if (y%2) t=(ll)t*x%mo;    return t;}void add(int x,int y){    go[++tot]=y;    nxt[tot]=h[x];    h[x]=tot;}void dfs(int x,int y){    father[x]=y;    dep[x]=dep[y]+1;    int t=h[x];    while (t){        if (go[t]!=y) dfs(go[t],x);        t=nxt[t];    }}int main(){    freopen("communicate.in","r",stdin);freopen("communicate.out","w",stdout);    srand(19890604);    scanf("%d",&n);    fo(i,1,n-1){        scanf("%d%d",&j,&k);        add(j,k);add(k,j);    }    dfs(rand()%n+1,0);    fo(i,1,n){        if (i==1){            num[i]++;            ans++;            now++;            continue;        }        //(ans+=now)%=mo;        ans+=now;        if (ans>=mo) ans-=mo;        r=ans;        /*j=i-1;k=i;        while (j!=k){            if (dep[j]>dep[k]) j=father[j];            else k=father[k];        }*/        j=i-1;k=i;        if (dep[j]<dep[k]) swap(j,k);        while (dep[j]>dep[k]) j=father[j];        while (j!=k){            j=father[j];            k=father[k];        }        l=j;        j=i-1;k=i;        while (j!=l){            //(ans+=(i-1)-num[j])%=mo;            ans+=(i-1)-num[j];            if (ans>=mo) ans-=mo;            //(now+=(i-1)-num[j])%=mo;            j=father[j];        }        while (k!=l){            //(ans+=(i-1)-num[k])%=mo;            ans+=(i-1)-num[k];            if (ans>=mo) ans-=mo;            //(now+=(i-1)-num[k])%=mo;            k=father[k];        }        //(ans+=(i-1)-num[l])%=mo;        ans+=(i-1)-num[l];        if (ans>=mo) ans-=mo;        //(now+=(i-1)-num[l])%=mo;        ans++;        //now++;        (now+=ans-r)%=mo;        (now+=mo)%=mo;        j=i-1;k=i;        while (j!=l){            num[j]=i-1;            j=father[j];        }        while (k!=l){            num[k]=i-1;            k=father[k];        }        num[l]=i-1;        num[i]++;    }    //ans=293;    ans=(2*ans%mo-2*n*(n+1)/2)%mo;    ans=(ll)ans*qsm(n*(n+1)/2,mo-2)%mo;    (ans+=mo)%=mo;    printf("%d\n",ans);    /*ans=490909103;    ans=(ll)ans*(n*(n-1)/2)%mo;*/    /*(ans+=n*(n-1))%=mo;    ans=(ll)ans*(mo+1)/2%mo;*/}
原创粉丝点击