[树形DP] BZOJ 4835 遗忘之树

来源:互联网 发布:什么是正定矩阵 编辑:程序博客网 时间:2024/06/09 15:41

一个不难的题吧 最后半小时才想到
树形DP咯 fu 表示点分树上子树u的方案数
之后呢 转移关键就是要乘上这级重心向下一级子树中的那个点连边
因为重心会有两个 而这里规定是编号小的优先
如果下一级子树中没有第二个重心 那么就连哪个都行
否则 只能连比u标号小的 我可能学傻 写了个主席树 能不能不要主席树我还不清楚
UPD. 直接暴力统计就好了
树高是O(logn)的 每个点只会被统计那么多次 总O(nlogn)

#include<cstdio>#include<cstdlib>#include<algorithm>using namespace std;typedef long long ll;inline char nc(){  static char buf[100000],*p1=buf,*p2=buf;  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void read(int &x){  char c=nc(),b=1;  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}const int N=100005;const int P=1e9+7;const int INV2=(P+1)>>1;ll fac[N],inv[N];inline void Pre(int n){  fac[0]=1; for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;  inv[1]=1; for (int i=2;i<=n;i++) inv[i]=(ll)(P-P/i)*inv[P%i]%P;  inv[0]=1; for (int i=1;i<=n;i++) inv[i]=inv[i-1]*inv[i]%P;}struct edge{  int u,v,next;}G[N<<1];int head[N],inum;#define V G[p].vinline void add(int u,int v,int p){  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;}const int K=25;int rt[N];int ls[K*N],rs[K*N],sum[K*N];  int ncnt;inline void Modify(int &y,int x,int l,int r,int t,int a){    y=++ncnt; int mid=(l+r)>>1;    if (l==r){      sum[y]=sum[x]+a; return;    }  if (t<=mid)       rs[y]=rs[x],Modify(ls[y],ls[x],l,mid,t,a),sum[y]=sum[ls[y]]+sum[rs[y]];    else      ls[y]=ls[x],Modify(rs[y],rs[x],mid+1,r,t,a),sum[y]=sum[ls[y]]+sum[rs[y]];  }inline int Query(int x,int l,int r,int ql,int qr){  if (!x) return 0;  if (ql<=l && r<=qr) return sum[x];  int mid=(l+r)>>1,ret=0;  if (ql<=mid) ret+=Query(ls[x],l,mid,ql,qr);  if (qr>mid) ret+=Query(rs[x],mid+1,r,ql,qr);  return ret;}ll f[N];int size[N];int pre[N],clk;int n,m;int deg[N];inline int QQ(int x,int y){  return Query(rt[pre[x]+size[x]-1],1,n,y+1,n)-Query(rt[pre[x]-1],1,n,y+1,n);}inline void dfs(int u,int fa){  size[u]=1; pre[u]=++clk;  Modify(rt[clk],rt[clk-1],1,n,u,1);  for (int p=head[u];p;p=G[p].next)    if (V!=fa)      dfs(V,u),size[u]+=size[V];  f[u]=1; int flag=0;  for (int p=head[u];p;p=G[p].next)    if (V!=fa){      f[u]=f[u]*f[V]%P;      if (size[u]<size[V]*2) flag=1;      if (size[u]==size[V]*2)    f[u]=f[u]*QQ(V,u)%P;      else    f[u]=f[u]*size[V]%P;    }  if (flag) f[u]=0;}int main(){  int T,iu,iv;  freopen("t.in","r",stdin);  freopen("t.out","w",stdout);  read(T); Pre(100000);  while (T--){    read(n); read(m);    for (int i=1;i<=n;i++) deg[i]=0;    for (int i=1;i<n;i++) read(iu),read(iv),add(iu,iv,++inum),deg[iv]=1;    int rt=0;    for (int i=1;i<=n;i++) if (!deg[i]) rt=i;    clk=0;dfs(rt,0);    printf("%lld\n",f[rt]);    inum=0;    for (int i=1;i<=n;i++) head[i]=0,::rt[i]=0;;    ncnt=0;  }  return 0;}
0 0
原创粉丝点击