hdu-5977 Garden of Eden(树分治)

题目链接:

Garden of Eden

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 210    Accepted Submission(s): 75

Problem Description

When God made the first man, he put him on a beautiful garden, the Garden of Eden. Here Adam lived with all animals. God gave Adam eternal life. But Adam was lonely in the garden, so God made Eve. When Adam was asleep one night, God took a rib from him and made Eve beside him. God said to them, “here in the Garden, you can do everything, but you cannot eat apples from the tree of knowledge.”
One day, Satan came to the garden. He changed into a snake and went to live in the tree of knowledge. When Eve came near the tree someday, the snake called her. He gave her an apple and persuaded her to eat it. Eve took a bite, and then she took the apple to Adam. And Adam ate it, too. Finally, they were driven out by God and began a hard journey of life.
The above is the story we are familiar with. But we imagine that Satan love knowledge more than doing bad things. In Garden of Eden, the tree of knowledge has n apples, and there are k varieties of apples on the tree. Satan wants to eat all kinds of apple to gets all kinds of knowledge.So he chooses a starting point in the tree,and starts walking along the edges of tree,and finally stops at a point in the tree(starting point and end point may be same).The same point can only be passed once.He wants to know how many different kinds of schemes he can choose to eat all kinds of apple. Two schemes are different when their starting points are different or ending points are different.

Input

There are several cases.Process till end of input.
For each case, the first line contains two integers n and k, denoting the number of apples on the tree and number of kinds of apple on the tree respectively.
The second line contains n integers meaning the type of the i-th apple. Types are represented by integers between 1 and k .
Each of the following n-1 lines contains two integers u and v,meaning there is one edge between u and v.1≤n≤50000, 1≤k≤10

Output

For each case output your answer on a single line.

Sample Input

3 2

1 2 2

1 2

1 3

Sample Output

6

题意:

给出一棵树,给出每个节点的颜色,问有多少对节点满足这个路径上的所有点的并为K种颜色;

思路:

一开始想用树形dp搞,然而MLE了,所以就是树分治了,模板往上一套就好了;注意每次寻找到了root就保存下来;

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=5e4+5;
int n,k,fk,a[maxn],p[13];
int siz[maxn],son[maxn],vis[maxn],root,MAX,cnt,num[1030],d[maxn],cn=0,head[maxn];
LL ans=0;
struct Edge
{
    int to,next;
}edge[2*maxn];
inline void add_edge(int from,int to)
{
    edge[cn].to=to;
    edge[cn].next=head[from];
    head[from]=cn++;
}
inline void init()
{
    cn=0;
    fk=(1<<k)-1;
    ans=0;
    for(int i=0;i<=n;i++)vis[i]=0;
        memset(head,-1,sizeof(head));
}
void get_siz(int cur,int fa)
{
    siz[cur]=1;
    son[cur]=0;
    for(int i=head[cur];i!=-1;i=edge[i].next)
    {
        int x=edge[i].to;
        if(x==fa||vis[x])continue;
        get_siz(x,cur);
        siz[cur]+=siz[x];
        if(siz[x]>son[cur])son[cur]=siz[x];
    }
}
void find_root(int cur,int fa,int rt)
{
    if(siz[rt]-siz[cur]>son[cur])son[cur]=siz[rt]-siz[cur];
    if(son[cur]<MAX)MAX=son[cur],root=cur;
    for(int i=head[cur];i!=-1;i=edge[i].next)
    {
        int x=edge[i].to;
        if(x==fa||vis[x])continue;
        find_root(x,cur,rt);
    }
}
void get_state(int cur,int fa,int sta)
{
    d[cnt++]=sta;
    num[sta]++;
    for(int i=head[cur];i!=-1;i=edge[i].next)
    {
        int x=edge[i].to;
        if(vis[x]||x==fa)continue;
        get_state(x,cur,a[x]|sta);
    }
}
LL cal(int cur,int sta)
{
    cnt=0;
    memset(num,0,sizeof(num));
    get_state(cur,0,sta);
    for(int i=0;i<k;i++)
    {
        for(int j=fk;j>=0;j--)
        {
            if(!(p[i]&j))num[j]+=num[j|p[i]];
        }
    }
    LL ret=0;
    for(int i=0;i<cnt;i++)ret=ret+num[fk^d[i]];
    return ret;
}
void dfs(int cur)
{
    MAX=n;
    get_siz(cur,0);
    find_root(cur,0,cur);
    int Root=root;
    ans=ans+cal(root,a[Root]);
    vis[root]=1;
    for(int j=head[Root];j!=-1;j=edge[j].next)
    {
        int x=edge[j].to;
        if(vis[x])continue;
        ans=ans-cal(x,(a[x]|a[Root]));
        dfs(x);
    }
}
int main()
{
    p[0]=1;for(int i=1;i<=11;i++)p[i]=p[i-1]*2;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i]=p[a[i]-1];
        }
        int u,v;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs(1);
        printf("%lld\n",ans);
    }
    return 0;
}

  

时间: 2024-08-28 11:04:25

hdu-5977 Garden of Eden(树分治)的相关文章

hdu 5977 Garden of Eden

Garden of Eden Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 581    Accepted Submission(s): 164 Problem Description When God made the first man, he put him on a beautiful garden, the Garden

HDU 4812 D Tree 树分治+逆元处理

D Tree Problem Description There is a skyscraping tree standing on the playground of Nanjing University of Science and Technology. On each branch of the tree is an integer (The tree can be treated as a connected graph with N vertices, while each bran

HDU 5102 树分治

The K-th Distance Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 202    Accepted Submission(s): 50 Problem Description Given a tree, which has n node in total. Define the distance between two

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1

poj 1744 tree 树分治

Tree Time Limit: 1000MS   Memory Limit: 30000K       Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of ve

HDU 3966 Aragorn&#39;s Story (树链点权剖分,成段修改单点查询)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 树链剖分的模版,成段更新单点查询.熟悉线段树的成段更新的话就小case啦. 1 //树链剖分 边权修改 单点查询 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespace std; 7 const int M

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

COJ 0970 WZJ的数据结构(负三十)树分治

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后

Codeforces 321C Ciel the Commander 树分治裸题

题目链接 题意: 给定一棵树,要用字母A-Z 填到每个节点上 字母可以无限使用,但A至多只能用一次 目标:对于任意两个相同字母的节点,他们之间的路径上必须有至少一个节点的字母比他们小 例如:在两个C之间至少要有一个A 或者一个B 问: 输出填涂方案. 树分治即可,最多支持2^25个节点,不会无解. #include <iostream> #include <string> #include <vector> #include <cstring> #inclu