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\n",s[1].size());
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值