hdu 5909 Tree Cutting——点分治(树形DP转为序列DP)

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

点分治的话,每次要做一次树形DP;但时间应该是 siz*m2 的。可以用 FWT 变成 siz*mlogm ,但这里写的是把树变成序列来 DP 的方法,应该是 nlogn*m 的。

树上的一个点,如果选,就可以选它的孩子,所以它向它的第一个孩子连边;如果不选,就会跳到它的下一个兄弟或者是父亲的下一个兄弟之类的,向那边连一条边。

做出树的 dfs 序,把边都连在 dfs 序上;其实那个第一条边一定连向自己 dfs 序+1,即使自己没有孩子也是符合的,所以可以不用连了;第二条边可以通过传父亲的连边对象来解决。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1005,M=1025,mod=1e9+7;
int T,n,m,w[N],hd[N],xnt,to[N<<1],nxt[N<<1],siz[N],rt,mn;
int dfn[N],tot,sta[N],top,f[N][M],g[N],nt[N],ans[M]; bool vis[N];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)fx=0;ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘)ret=ret*10+ch-‘0‘,ch=getchar();
  return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
void upd(int &x){x>=mod?x-=mod:0;}
void init()
{
  xnt=0;memset(hd,0,sizeof hd);
  memset(ans,0,sizeof ans); memset(vis,0,sizeof vis);
}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void getrt(int cr,int fa,int s)
{
  siz[cr]=1; int mx=0;
  for(int i=hd[cr],v;i;i=nxt[i])
    if(!vis[v=to[i]]&&v!=fa)
      {
    getrt(v,cr,s);siz[cr]+=siz[v];
    mx=Mx(mx,siz[v]);
      }
  mx=Mx(mx,s-siz[cr]);if(mx<mn)mn=mx,rt=cr;
}
void dfs(int cr,int fa)
{
  dfn[cr]=++tot;g[tot]=w[cr];
  for(int i=hd[cr],v;i;i=nxt[i])
    if(!vis[v=to[i]]&&v!=fa)dfs(v,cr);
}
void dfsx(int cr,int fa,int lst)
{
  nt[dfn[cr]]=lst;
  int l=top+1;
  for(int i=hd[cr],v;i;i=nxt[i])
    if(!vis[v=to[i]]&&v!=fa)sta[++top]=v;
  int r=top;
  for(int i=hd[cr],v,p0=l;i;i=nxt[i])
    if(!vis[v=to[i]]&&v!=fa)
      {
    dfsx(v,cr,p0==r?lst:dfn[sta[p0+1]]);p0++;
      }
}
void solve(int cr,int s)
{
  vis[cr]=1;
  tot=0;dfs(cr,0);top=0;dfsx(cr,0,s+1);
  for(int i=1;i<=s+1;i++)memset(f[i],0,sizeof f[i]);
  f[1][0]=1;
  for(int i=1;i<=s;i++)
    for(int j=0;j<m;j++)
      {
    if(!f[i][j])continue;
    f[i+1][j^g[i]]+=f[i][j];upd(f[i+1][j^g[i]]);
    f[nt[i]][j]+=f[i][j];upd(f[nt[i]][j]);
      }
  f[s+1][0]--;//dec the empty
  for(int j=0,k=s+1;j<m;j++)ans[j]+=f[k][j],upd(ans[j]);
  for(int i=hd[cr],v,ts;i;i=nxt[i])
    if(!vis[v=to[i]])
      {
    ts=(siz[cr]>siz[v]?siz[v]:s-siz[cr]);
    mn=N;getrt(v,cr,ts);solve(rt,ts);
      }
}
int main()
{
  T=rdn();
  while(T--)
    {
      n=rdn();m=rdn();for(int i=1;i<=n;i++)w[i]=rdn();
      init();
      for(int i=1,u,v;i<n;i++)u=rdn(),v=rdn(),add(u,v),add(v,u);
      mn=N;getrt(1,0,n);solve(rt,n);
      for(int i=0,j=m-1;i<j;i++)printf("%d ",ans[i]);
      printf("%d\n",ans[m-1]);
    }
  return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/10182918.html

时间: 2024-10-13 22:31:33

hdu 5909 Tree Cutting——点分治(树形DP转为序列DP)的相关文章

HDU 5909 Tree Cutting

传送门 题意: 有一棵n个点的无根树,节点依次编号为1到n,其中节点i的权值为vi, 定义一棵树的价值为它所有点的权值的异或和. 现在对于每个[0,m)的整数k,请统计有多少T的非空连通子树的价值等于k. Sample Input 2 4 4 2 0 1 3 1 2 1 3 1 4 4 4 0 1 3 1 1 2 1 3 1 4 Sample Output 3 3 2 3 2 4 2 3 令f[i][j]表示以i为根的子树中异或和为j的联通块个数,v为i儿子 f[i][j]+=f[i][k]*f

HDU 5293 TREE CHAIN PROBLEM LCT+树形DP

题解链接 代码链接 链接 Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 35    Accepted Submission(s): 8 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1

【HDU 5909】 Tree Cutting (树形依赖型DP+点分治)

Tree Cutting Problem Description Byteasar has a tree T with n vertices conveniently labeled with 1,2,...,n. Each vertex of the tree has an integer value vi. The value of a non-empty tree T is equal to v1⊕v2⊕...⊕vn, where ⊕ denotes bitwise-xor. Now fo

fwt优化+树形DP HDU 5909

1 //fwt优化+树形DP HDU 5909 2 //见官方题解 3 // BestCoder Round #88 http://bestcoder.hdu.edu.cn/ 4 5 #include <bits/stdc++.h> 6 // #include <iostream> 7 // #include <cstdio> 8 // #include <cstdlib> 9 // #include <algorithm> 10 // #inc

hdu 5293 Tree chain problem(树链剖分+树形dp)

题目链接:hdu 5293 Tree chain problem 维护dp[u], sum[u],dp[u]表示以u为根节点的子树的最优值.sum[u]表示以u节点的所有子节点的dp[v]之和.对于边a,b,w,在LCA(a,b)节点的时候进行考虑.dp[u] = min{dp[u], Sum(a,b) - Dp(a,b) + sum[u] | (ab链上的点,不包括u } #pragma comment(linker, "/STACK:1024000000,1024000000")

(中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.Find out the

HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形dp, 对于每条链u,v,w,我们只在lca(u,v)的顶点上处理它 让dp[i]表示以i为根的指数的最大值,sum[i]表示dp[vi]的和(vi为i的儿子们) 则i点有两种决策,一种是不选以i为lca的链,则dp[i]=sum[i]. 另一种是选一条以i为lca的链,那么有转移方程:dp[i]=

HDU 3534 Tree (经典树形dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3534 题意: 给你一棵树,问你有多少对点的距离等于树的直径. 思路: dp[i][0]表示在i的子树中 离i最远的距离,dp[i][1]是次远距离.   cnt[i][0]则是最远的点的数量,cnt[i][1]表示次远的数量. up[i]表示以i向上 离i最远的距离.   up_cnt[i]表示向上最远的数量. 写的有点麻烦,调试了2小时... 1 //#pragma comment(linker,

hdu 3534 Tree(树形DP)

题目链接:hdu 3534 Tree 题意: 给你一棵n个节点,n-1条边的树,每条边有一个长度,现在问你最长的边的长度为多少,有多少条. 题解: 其实这种题不用记录最长和次长,我们开两个数组,len[i],num[i]. 表示以i为根结点出发的最长的长度以及最长的边的条数. 然后我们只需要一个dfs,先用子节点的信息来更新答案,然后在更新当前节点的len和num记录的信息. 这样就不用记录最长和次长. 1 #include<bits/stdc++.h> 2 #define mst(a,b)