CodeForces - 613D:Kingdom and its Cities(虚树+DP)

Meanwhile, the kingdom of K is getting ready for the marriage of the King‘s daughter. However, in order not to lose face in front of the relatives, the King should first finish reforms in his kingdom. As the King can not wait for his daughter‘s marriage, reforms must be finished as soon as possible.

The kingdom currently consists of n cities. Cities are connected by n - 1 bidirectional road, such that one can get from any city to any other city. As the King had to save a lot, there is only one path between any two cities.

What is the point of the reform? The key ministries of the state should be relocated to distinct cities (we call such cities important). However, due to the fact that there is a high risk of an attack by barbarians it must be done carefully. The King has made several plans, each of which is described by a set of important cities, and now wonders what is the best plan.

Barbarians can capture some of the cities that are not important (the important ones will have enough protection for sure), after that the captured city becomes impassable. In particular, an interesting feature of the plan is the minimum number of cities that the barbarians need to capture in order to make all the important cities isolated, that is, from all important cities it would be impossible to reach any other important city.

Help the King to calculate this characteristic for each of his plan.

Input

The first line of the input contains integer n (1 ≤ n ≤ 100 000) — the number of cities in the kingdom.

Each of the next n - 1 lines contains two distinct integers uivi (1 ≤ ui, vi ≤ n) — the indices of the cities connected by the i-th road. It is guaranteed that you can get from any city to any other one moving only along the existing roads.

The next line contains a single integer q (1 ≤ q ≤ 100 000) — the number of King‘s plans.

Each of the next q lines looks as follows: first goes number ki — the number of important cities in the King‘s plan, (1 ≤ ki ≤ n), then follow exactly ki space-separated pairwise distinct numbers from 1 to n — the numbers of important cities in this plan.

The sum of all ki‘s does‘t exceed 100 000.

Output

For each plan print a single integer — the minimum number of cities that the barbarians need to capture, or print  - 1 if all the barbarians‘ attempts to isolate important cities will not be effective.

Examples

Input

41 32 34 342 1 23 2 3 43 1 2 44 1 2 3 4

Output

1-11-1

Input

71 22 33 41 55 65 714 2 4 6 7

Output

2

Note

In the first sample, in the first and the third King‘s plan barbarians can capture the city 3, and that will be enough. In the second and the fourth plans all their attempts will not be effective.

In the second sample the cities to capture are 3 and 5.

题意:这两天看了不少的关于虚树的题目,有些许收获,然后此题算是最简单,先写此题。

思路:用DP或者贪心可以解决此题,但是由于每一次的复杂度都是O(N),而每一次的可用点是不多的,注意到sigma(K)<1e5,显然需要建立虚树,在虚树上做DP或者贪心。

看到很多种虚树的写法,这个比较好记:

1,先按DFS序排序,然后得到相邻的LCA,加入点集,去重。

2,建虚树,维护一个栈,对于当前要加入的点,如果它不在栈顶的点的子树内(也就是代码里的belong,用dfs序很方便的判断),我们就一直退栈,然后栈顶向当前点连边即可。(队列里维护的是一条从根到此点的dep递增的DFS链

得到虚树后就可以DP了:

从下向上遍历,如果当前点是染色的点,那么它需要和染色儿子切断。如果不是染色的点,当染色儿子大于1时,需要去掉此点;当染色儿子等于1时,不用管。

#include<bits/stdc++.h>
const int maxn=100010;
using namespace std;
int Laxt[maxn],Next[maxn<<1],To[maxn<<1],dep[maxn],cnt;
int in[maxn],out[maxn],fa[maxn][18],times,a[maxn];
int q[maxn],col[maxn],sz[maxn],top,tot,ans;
vector<int>G[maxn];
void add(int u,int v){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; }
bool cmp(int x,int y){ return in[x]<in[y]; }
void dfs1(int u,int f)
{
    in[u]=++times; fa[u][0]=f; dep[u]=dep[f]+1;
    for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f) dfs1(To[i],u);
    out[u]=times;
}
int LCA(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=17;i>=0;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
    if(u==v) return u;
    for(int i=17;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
bool belong(int x,int y){ return in[x]>=in[y]&&in[x]<=out[y]; } //判断x是否在y的子树里。
bool check()
{
    for(int i=1;i<=tot;i++)
       if(col[fa[a[i]][0]]) return false;
    return true;
}
void build()  //建立虚树
{
    top=0; for(int i=1;i<=tot;i++){
        while(top&&!belong(a[i],q[top])) top--;
        if(top) G[q[top]].push_back(a[i]);
        q[++top]=a[i];
    }
}
void dfs2(int u) //DP
{
    int L=G[u].size();
    for(int i=0;i<L;i++){
        dfs2(G[u][i]);
        sz[u]+=sz[G[u][i]];
    }
    if(col[u]) ans+=sz[u],sz[u]=1;
    else if(sz[u]>1) ans++,sz[u]=0;
}
int main()
{
    int N,Q,K,u,v,i,j;
    scanf("%d",&N);
    for(i=1;i<N;i++){
        scanf("%d%d",&u,&v);
        add(u,v); add(v,u);
    }
    dfs1(1,0);
    for(i=1;i<=17;i++)
      for(j=1;j<=N;j++)
         fa[j][i]=fa[fa[j][i-1]][i-1];
    scanf("%d",&Q);
    while(Q--){
        scanf("%d",&K); tot=K;     ans=0;
        for(i=1;i<=K;i++) scanf("%d",&a[i]),col[a[i]]=1;
        if(!check()){ puts("-1"); for(i=1;i<=K;i++) col[a[i]]=0; continue; }
        sort(a+1,a+tot+1,cmp);
        for(i=2;i<=K;i++) a[++tot]=LCA(a[i-1],a[i]);
        sort(a+1,a+tot+1,cmp);
        tot=unique(a+1,a+tot+1)-(a+1);
        build();
        dfs2(a[1]);
        printf("%d\n",ans);
        for(i=1;i<=tot;i++) col[a[i]]=sz[a[i]]=0,G[a[i]].clear();
    }
    return 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/9279422.html

时间: 2024-09-30 18:58:52

CodeForces - 613D:Kingdom and its Cities(虚树+DP)的相关文章

CF613D Kingdom and its Cities 虚树

传送门 $\sum k \leq 100000$虚树套路题 设$f_{i,0/1}$表示处理完$i$以及其所在子树的问题,且处理完后$i$点存在$0/1$个没有被封住的关键点时的最小代价,转移考虑$i$是否是关键点,随便转就行了 1 #include<bits/stdc++.h> 2 //This code is written by Itst 3 using namespace std; 4 5 inline int read(){ 6 int a = 0; 7 bool f = 0; 8

Codeforces 1111E Tree 虚树 + dp

直接把 r 加进去建虚树, 考虑虚树上的dp, 我们考虑虚树的dfs序的顺序dp过去. dp[ i ][ j ]  表示到 i 这个点为止, 分成 j 组有多少种合法方案. dp[ i ][ j ] = dp[ i - 1 ][ j ] * (j - have[ i ])  + dp[ i - 1 ][ j - 1 ], have[ i ] 表示 i 的祖先中有多少个在a中出现. #include<bits/stdc++.h> using namespace std; const int N

bzoj 3572 [Hnoi2014]世界树(虚树+DP)

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.     世界树的形态可以用一个数学模型来描述:世界树中有n个

BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$(f,x)$,讨论一下边上的点的子树应该靠谁更近 倍增求出分界点 注意有些没出现在虚树上的子树 注意讨论的时候只讨论链上的不包括端点,否则$f$的子树会被贡献多次 学到的一些$trick:$ 1.$pair$的妙用 2.不需要建出虚树只要求虚树的$dfs$序(拓扑序)和$fa$就可以$DP$了 注意

HDU-6035:Colorful Tree(虚树+DP)

这里有三道长得像的题: 一:HDU6036: There is a tree with nn nodes, each of which has a type of color represented by an integer, where the color of node ii is cici. The path between each two different nodes is unique, of which we define the value as the number of

codeforces 573B B. Bear and Blocks(线段树+dp)

题目链接: codeforces 573B 题目大意: 给出n个连续塔,每个塔有高度hi,每次取走最外层的块,问需要多少次操作能够拿光所有的块. 题目分析: 首先我们可以知道第一次操作时,对于每个塔的变化满足如下的公式: hi=min(hi?1,hi?1,hi+1) 每次操作都满足如下的递推式,我们递推一下得到第k次操作第i的塔的高度: hi=max(0,minj=0i{min(hi?j?(k?j),hi+j?(k?j)}?hi=max(0,minj=0i{min(hi?j+j?k,hi+j+j

codeforces#426(div1) B - The Bakery (线段树 + dp)

题意:把 n 个数划分成 m 段,要求每组数不相等的数的数量最大之和. 思路: dp方程 : dp[i][j] = max( dp[k][j-1] + v(k, i) );( j<=k<i , k = j, j+1, +...+ i-1) dp[i][j]表示第 i 个数分到第 j 段的最大值. v(k, i) 表示k~i中不同数的个数,此处用hash记录每个数上一次出现的位置,从上一次出现的位置到当前位置的 dp[i][j-1] 值均可+1. 此时时间复杂度 O(n*m*log(n)). 线

BZOJ 3611: [Heoi2014]大工程 [虚树 DP]

传送门 题意: 多次询问,求最长链最短链链总长 煞笔$DP$记录$d,c,f,g$ $MD$该死拍了一下午没问题然后交上去就$T$ 然后发现树链剖分写成$size[v]+=size[u]$ 我想知道我随机生成的大数据是怎么跑过去的!!!!!!!! #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using

Codeforces Round #277 (Div. 2)Valid Sets 树DP

题意:给出一棵树,并给出每个节点上的权值,求有多少个连通子块的最大值与最小值的差不超过d. 对于每个顶点建立一颗树,然后找比它价值大的   或者   价值相等且之前没有被当作顶点建立树的点,这样就避免重复了. dp[x]表示包涵x且以x为顶点的连通子树的个数,dp[x] = ∏ (dp[son[x]] + 1). 注意要用long long . #include<iostream> #include<iostream> #include<cstdio> #include