zjnu1709 UZASTOPNI (bitset,树形dp)

Description


Petar is throwing a birthday party and he decided to invite some of the employees of his company where he is the CEO. Each employee, including Petar, has a unique label from 1 to N, and an accompanying type of jokes they tell Vi . Also, each employee of the company except Petar has exactly one supervisor. Since Petar is the CEO of the company, he has the label 1 and is directly or indirectly superordinate to all the employees. At the birthday party, there are certain rules that all people present (including Petar) must follow.


• At the party, there shouldn’t be two people that tell the same type of jokes.


• Person X cannot be invited if their direct supervisor is not invited.


• Person X cannot be invited if the set of jokes the invitees that person X is superior to (directly or indirectly) tell and person X don’t form a set of consecutive numbers.


The numbers in the set are consecutive if the difference between adjacent elements is exactly 1 when the set is sorted ascendingly. For example, (3, 1, 2) and (5, 1, 2, 4, 3). Petar wants to know how many different sets of jokes he can see at his party with the listed constraints.


Input


The first line of input contains the integer N, (1 ≤ N ≤ 10 000). The second line of input contains N integers, the types of jokes person i tells, Vi, (1 ≤ Vi ≤ 100). Each of the following N-1 lines contains two integers A and B, (1 ≤ A, B ≤ N), denoting that person A is directly superior to person B.


Output


The first and only line of output must contain the number of different sets of jokes that comply to the previously listed constraints.


Sample Input




4
2 1 3 4
1 2
1 3
3 4


4
3 4 5 6
1 2
1 3
2 4


6
5 3 6 4 2 1
1 2
1 3
1 4
2 5
5 6 
Sample Output




6
3

10


题意:n个点形成一棵树,每一个点有自己的价值,让你在满足这3个条件的前提下找到总的方案数:1.一个节点的父亲节点没有选择时,该节点不能选择.2.选择的点构成的集合中不能存在相同价值的两个点.3.选择的任何一棵子树(包含本身)价值所构成的集合一定是连续的.

思路:可以递归求解,我们假设一个节点的子树都处理完了,那么先把子树中所有得到的可行的区间都记录下来,然后枚举所有左端点(1~100),然后找出可行的右端点,可以用bitset处理。


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 600000
#define maxn 10050
#define l first
#define r second
int v[maxn];
vector<int>e[maxn];  //存储边
bitset<105>flag[maxn][105]; //flag[i][j]表示第i个节点左端点为j,右端点的方案数
vector<int>p[105];  //p[i]表示该节点子树中左端点为i的右端点们
vector<pair<int,int> >s[maxn];  //s[i]表示节点为i的符合条件的区间们


void dfs(int u)
{
    int i,j,k,lo,re;
    for(i=0;i<e[u].size();i++){
        dfs(e[u][i]);
    }

    for(i=1;i<=100;i++)p[i].clear();

    for(i=0;i<e[u].size();i++){
        int v=e[u][i];
        for(j=0;j<s[v].size();j++){
            p[s[v][j].l ].push_back(s[v][j].r);
        }
    }
    for(lo=100;lo>=1;lo--){
        if(lo==v[u]){
            flag[u][lo]|=flag[u][lo+1];
            flag[u][lo].set(lo);
        }
        else{
            for(i=0;i<p[lo].size();i++){
                re=p[lo][i];
                if(lo>v[u] || re<v[u]){
                    flag[u][lo]|=flag[u][re+1];
                    flag[u][lo].set(re);
                }
            }
        }
        for(re=lo;re<=100;re++){
            if(flag[u][lo].test(re)==1 && lo<=v[u] && re>=v[u]){
                s[u].push_back(make_pair(lo,re) );
            }
        }
    }
}
int main()
{
    int n,m,i,j,c,d;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++){
            scanf("%d",&v[i]);
        }
        for(i=1;i<=n-1;i++){
            scanf("%d%d",&c,&d);
            e[c].push_back(d);
        }
        dfs(1);
        printf("%d
",s[1].size());
    }
    return 0;
}



原文地址:https://www.cnblogs.com/herumw/p/9464524.html