51Nod1679 连通率
一个简单的计数问题
我们先考虑O(n^2)的做法
对每个点dfs一次,求出d[i]表示i的深度,那么对答案贡献就是Σ2^(n-d[i])
那么我们考虑用数据结构动态维护这个d[i],显然可以用线段树来维护dfs序做到
复杂度O(n lg n) 效率很高rank8
看了下solution突然才发现别人都不是这么做的!
不管了反正跑得过而且跑的快。。就是代码比较丑陋
#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define M 1000000007
#define LL long long
#define mid (l+r>>1)
#define N 100010
using namespace std;
const int inv=500000004;
struct edge{ int v,nt; } G[N<<1];
int n,cnt=0,h[N],w[N],t,d[N],l[N],r[N]; LL s[N<<2],c[N<<2],ans=0;
inline void ad(LL& x,LL y){ x=(x+y)%M; }
inline void mul(LL& x,LL y){ x=x*y%M; }
inline LL pow(LL x,LL k,LL s=1){
for(;k;x=x*x%M,k>>=1) k&1?s=s*x%M:0;
return s;
}
inline void build(int l,int r,int x){
if(l==r){ s[x]=pow(2,n-d[w[l]]-1); c[x]=1; return; }
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
s[x]=(s[x<<1]+s[x<<1|1])%M; c[x]=1;
}
inline void pd(int x){
if(c[x]>1){
mul(c[x<<1],c[x]);
mul(c[x<<1|1],c[x]);
mul(s[x<<1],c[x]);
mul(s[x<<1|1],c[x]);
c[x]=1;
}
}
inline void update(int l,int r,int x,int L,int R,LL k){
if(L<=l && r<=R){ mul(s[x],k); mul(c[x],k); return; }
pd(x);
if(L<=mid) update(l,mid,x<<1,L,R,k);
if(mid<R) update(mid+1,r,x<<1|1,L,R,k);
s[x]=(s[x<<1]+s[x<<1|1])%M;
}
inline LL query(int l,int r,int x,int L,int R){
if(L<=l && r<=R) return s[x];
pd(x); LL ans=0;
if(L<=mid) ad(ans,query(l,mid,x<<1,L,R));
if(mid<R) ad(ans,query(mid+1,r,x<<1|1,L,R));
return ans;
}
inline void dfs(int x){
w[++t]=x; l[x]=t;
for(int v,i=h[x];i;i=G[i].nt)
if(!l[v=G[i].v]){ d[v]=d[x]+1; dfs(v); }
r[x]=t;
}
inline void cal(int x,int p){
ad(ans,query(1,n,1,1,n));
for(int v,i=h[x];i;i=G[i].nt)
if((v=G[i].v)!=p){
update(1,n,1,l[v],r[v],4);
update(1,n,1,1,n,inv);
cal(v,x);
update(1,n,1,l[v],r[v],(LL)inv*inv%M);
update(1,n,1,1,n,2);
}
}
int main(){
scanf("%d",&n);
for(int x,y,i=1;i<n;++i){
scanf("%d%d",&x,&y);
G[++cnt]=(edge){y,h[x]}; h[x]=cnt;
G[++cnt]=(edge){x,h[y]}; h[y]=cnt;
}
dfs(1);
build(1,n,1);
cal(1,0);
ad(ans,-n*pow(2,n-1)%M);
printf("%lld\n",(ans+M)%M*inv%M);
}