hdu5927 好题

Auxiliary Set

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 516    Accepted Submission(s): 148


Problem Description
Given a rooted tree with n vertices, some of the vertices are important.

An auxiliary set is a set containing vertices satisfying at least one of the two conditions:

It is an important vertex
It is the least common ancestor of two different important vertices.

You are given a tree with n vertices (1 is the root) and q queries.

Each query is a set of nodes which indicates the  unimportant vertices in the tree. Answer the size (i.e. number of vertices) of the auxiliary set for each query.
 

Input
The first line contains only one integer T ( T1000 ), which indicates the number of test cases.

For each test case, the first line contains two integers n ( 1n100000 ), q ( 0q100000 ).

In the following n -1 lines, the i-th line contains two integers  ui,vi(1ui,vin)  indicating there is an edge between  ui i and  vi  in the tree.

In the next q lines, the i-th line first comes with an integer  mi(1mi100000)  indicating the number of vertices in the query set.Then comes with mi different integers, indicating the nodes in the query set.

It is guaranteed that  qi=1mi100000 .

It is also guaranteed that the number of test cases in which  n1000   or  qi=1mi1000  is no more than 10.
 

Output
For each test case, first output one line "Case #x:", where x is the case number (starting from 1).

Then q lines follow, i-th line contains an integer indicating the size of the auxiliary set for each query. 
 

Sample Input
  
  
1 6 3 6 4 2 5 5 4 1 5 5 3 3 1 2 3 1 5 3 3 1 4
 

Sample Output
  
  
Case #1: 3 6 3
Hint
For the query {1,2, 3}: •node 4, 5, 6 are important nodes For the query {5}: •node 1,2, 3, 4, 6 are important nodes •node 5 is the lea of node 4 and node 3 For the query {3, 1,4}: • node 2, 5, 6 are important nodes

题意:

根节点为1的树,定义一个节点为重要的节点至少满足两个条件中的一个条件

1:自己本身是重要的点

2:两个以上的子孙是重要的点

q组询问给出m个不重要的点
输出树上有多少重要的点
每次询问给出的是不重要点,如果重要点有两个以上重要点子孙,那么这个不重要点也变成集合里的一员,
每次输出集合里元素个数,将不重要点按照深度排序,然后遍历不重要点,如果不重点的孩子个数为0,那么
他的父亲孩子数减一,因为在他的父亲那里,他这个孩子没有孩子,并且自身还是不重要点,那么他父亲要这个孩子没有什么用,所以父亲节点孩子数减一;当这个不重点有两个及两个以上孩子,那么他也归属集合里; 儿子只对父亲影 响, 我们从最深的节点开始遍历 ,当遍历当前节点时此时所有孩子都是重要点。即便有个孩子是不重要点,但是这个孩子肯定有重要点的子孙,不然他的孩子数会变为0,假如他变为0了,就会影响父亲节点,父亲节点减一;
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <set>
#include <queue>
const int maxn = 1e6+10;

using namespace std;
struct node
{
    int next,v;
}edge[maxn];
//vector<int>G[maxn];
int tot,head[maxn];
int son[maxn],fa[maxn];
int dep[maxn];
int st[maxn];
//set<int>::iterator it;
int vis[maxn];
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
}
void add_edge(int u,int v)
{
    edge[tot].v=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void bdfs(int root)
{
    memset(vis,0,sizeof(vis));
    vis[root]=1;
    queue<int>que;
    que.push(root );
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v;;
            if(!vis[v])
            {
                son[u]++;
                fa[v]=u;
                dep[v]=dep[u]+1;
                que.push(v);
                vis[v]=1;
            }
        }
    }
}
bool cmp(int a,int  b)
{
    return dep[a]>dep[b];
}
int chang[maxn];
int main()
{
    int m;
    int t,n,q;
    int u,v;
    scanf("%d",&t);
    for(int cas=1; cas<=t; cas++)
    {
        scanf("%d%d",&n,&q);
        init();
        for(int i=1; i<n; i++)
        {
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        memset(dep,0,sizeof(dep));
        memset(son,0,sizeof(son));
        memset(fa,0,sizeof(fa));
        bfs(1);
        printf("Case #%d:\n",cas);
        while(q--)
        {
            scanf("%d",&m);
            for(int i=0; i<m; i++)
                scanf("%d",&st[i]);
            int ans=0;
            sort(st,st+m,cmp);
            for(int i=0; i<m; i++)
            {
                if(son[st[i]]==0)
                {
                    son[fa[st[i]]]--;
                    chang[fa[st[i]]]++;
                }
                if(son[st[i]]>=2)
                    ans++;
            }
            printf("%d\n",n-m+ans);
            for(int i=0; i<m; i++)
            {
                if(chang[fa[st[i]]])
                {
                    son[fa[st[i]]]+=chang[fa[st[i]]];
                    chang[fa[st[i]]]=0;
                }
            }
        }
    }
    return 0;
}
事实证明这样建图比vector快,因为vector居然超时了;



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值