传送门
文章目录
- 题意:
- 思路:
题意:
n≤1e5,∑k≤1e5,q≤1e5n\le1e5,\sum k\le1e5,q\le1e5n≤1e5,∑k≤1e5,q≤1e5。
思路:
经过分析,外敌占领的城市只有可能是两点的lcalcalca或者两点之间任意一点,是哪个点无所谓,所以我们首先检查一下是否存在两个重要城市互为父子,否则的话一定有解。
由于存在大量不重要的点,所以我们按照重要的城市建立一颗虚树,让后在虚树上dpdpdp,每个点分两种情况:
(1)(1)(1)这个点是重要城市,那么他必须与所有有重要城市的儿子之间断开。
(2)(2)(2)这个点不是重要城市,那么如果儿子也没有重要城市就对答案无贡献。如果儿子有一个重要城市,那么将这个城市也变成重要城市即可,相当于标记上传了,对答案也无贡献。如果儿子有多于111个重要城市,那么只需要将当前这个点占领即可,答案加一。
最后不要忘记清空数据,清空的时候可以再遍历一次清空即可。
// Problem: D. Kingdom and its Cities
// Contest: Codeforces - Codeforces Round #339 (Div. 1)
// URL: https://codeforces.com/problemset/problem/613/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int n,m;
vector<int>v[N];
int a[N],tot;
int stk[N],top;
int dfn[N],idx,fa[N][20],depth[N];
int has[N],ans;void dfs1(int u,int f) {fa[u][0]=f; dfn[u]=++idx;depth[u]=depth[f]+1;for(int i=1;i<=18;i++) fa[u][i]=fa[fa[u][i-1]][i-1];for(auto x:v[u]) {if(x==f) continue;dfs1(x,u);}
}int lca(int a,int b) {if(depth[a]<depth[b]) swap(a,b);for(int i=18;i>=0;i--) if(depth[fa[a][i]]>=depth[b]) a=fa[a][i];if(a==b) return a;for(int i=18;i>=0;i--)if(fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];return fa[a][0];
}bool check() {for(int i=1;i<=tot;i++) {if(has[fa[a[i]][0]]) return true;}return false;
}bool cmp(int a,int b) {return dfn[a]<dfn[b];
}void insert(int x) {if(!top) stk[++top]=x;else {int father=lca(x,stk[top]);while(top>1&&depth[father]<depth[stk[top-1]]) {v[stk[top-1]].pb(stk[top]),top--;}if(depth[father]<depth[stk[top]]) v[father].pb(stk[top--]);if(!top||(stk[top]!=father)) stk[++top]=father;stk[++top]=x;}
}void dfs2(int u,int f) {if(has[u]) {int add=0;for(auto x:v[u]) {if(x==f) continue;dfs2(x,u);add+=has[x]>0;}ans+=add;} else {int add=0;for(auto x:v[u]) {if(x==f) continue;dfs2(x,u);add+=has[x]>0;}if(add>1) ans++;else if(add==1) has[u]=1;}
}void dfs3(int u,int f) {//printf("%d**\n",u);has[u]=0;for(auto x:v[u]) {if(x==f) continue;dfs3(x,u);}v[u].clear();
}int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);scanf("%d",&n);for(int i=1;i<=n-1;i++) {int a,b; scanf("%d%d",&a,&b);v[b].pb(a); v[a].pb(b);}dfs1(1,0);for(int i=1;i<=n;i++) v[i].clear();scanf("%d",&m);while(m--) {scanf("%d",&tot);for(int i=1;i<=tot;i++) scanf("%d",&a[i]),has[a[i]]=1;if(check()) {for(int i=1;i<=tot;i++) has[a[i]]=0;puts("-1");continue;}sort(a+1,a+1+tot,cmp); top=0; ans=0;if(a[1]!=1) stk[++top]=1;for(int i=1;i<=tot;i++) insert(a[i]);while(top>1) v[stk[top-1]].pb(stk[top]),top--; dfs2(1,0); dfs3(1,0);printf("%d\n",ans);}return 0;
}
/**/