hdu 5909 Tree Cutting —— 点分治

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5909

点分治,每次的 rt 是必选的点;

考虑必须选根的一个连通块,可以DP,决策就是在每个子树中决定选不选子树根,如果不选就跳过这个子树;

于是可以转化成 dfs 序上的DP;

每次重新标记一遍 dfs 序,但不改动 siz (也许可以改动但T了?),可能因为 siz 还和点分治的过程有关。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const xn=1025,inf=1025,mod=1e9+7;
int n,m,v[xn],hd[xn],ct,to[xn<<1],nxt[xn<<1],siz[xn],dfn[xn],g[xn],tim;
int ans[xn],f[xn][xn],rt,mx,nt[xn];
bool vis[xn];
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return f?ret:-ret;
}
void upt(int &x,int y){x+=y; while(x>=mod)x-=mod; while(x<0)x+=mod;}
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
void getrt(int x,int fa,int sum)
{
  int nmx=0; siz[x]=1;
  for(int i=hd[x],u;i;i=nxt[i])
    {
      if((u=to[i])==fa||vis[u])continue;
      getrt(u,x,sum); siz[x]+=siz[u];
      if(siz[u]>nmx)nmx=siz[u];
    }
  nmx=max(nmx,sum-siz[x]);
  if(nmx<mx)mx=nmx,rt=x;
}
void dfs(int x,int fa)
{
  dfn[x]=++tim; g[tim]=v[x];
  for(int i=hd[x],u;i;i=nxt[i])
    if((u=to[i])!=fa&&!vis[u])dfs(u,x);
  nt[dfn[x]]=tim+1;
}
void work(int x,int ss)
{
  vis[x]=1; tim=0; dfs(x,0);
  for(int i=1;i<=ss+1;i++)memset(f[i],0,sizeof f[i]);
  f[2][g[1]]=1;
  for(int i=2;i<=ss;i++)
    for(int j=0;j<m;j++)
      if(f[i][j])upt(f[i+1][j^g[i]],f[i][j]),upt(f[nt[i]][j],f[i][j]);
  //printf("x=%d ss=%d
",x,ss);
  for(int j=0;j<m;j++)upt(ans[j],f[ss+1][j]);
  //,printf("f[%d][%d]=%d
",dfn[x]+siz[x],j,f[dfn[x]+siz[x]][j]);
  for(int i=hd[x],u;i;i=nxt[i])
    if(!vis[u=to[i]])
      {
    int ns=(siz[u]>siz[x]?ss-siz[x]:siz[u]);
    mx=inf; getrt(u,0,ns); work(rt,ns);
      }
}
int main()
{
  int T=rd();
  while(T--)
    {
      n=rd(); m=rd(); 
      for(int i=1;i<=n;i++)v[i]=rd();
      ct=0; tim=0;
      for(int i=1;i<=n;i++)hd[i]=0;
      for(int i=1,x,y;i<n;i++)x=rd(),y=rd(),add(x,y),add(y,x);
      for(int j=0;j<m;j++)ans[j]=0;
      for(int i=1;i<=n;i++)vis[i]=0;
      mx=inf; getrt(1,0,n); work(rt,n);
      for(int j=0;j<m;j++)printf("%d%c",ans[j],j==m-1?'
':' ');
    }
  return 0;
}
原文地址:https://www.cnblogs.com/Zinn/p/10183035.html