题意:给定一棵以1为根的n个节点的树,多个询问,每次询问给出一个集合,集合内的点表示为不重要的点(不在集合内的点就是重要的点),求给定这个集合后有多少点能进入另一个集合,点x进入另一个集合的要求:1:重要的点。2:有两个重要的点的最近公共祖先为x。
分析:其实对于每一个询问我们只要判断哪些不重要的点是能进入集合的,那么对于一个不重要的点x,怎样才能进入集合呢?我们先dfs对于所有的点求出fa[x]和son[x]。当询问是,我们先初始确定每个不重要的点的son'[x],如果一个点要进入集合那么显然要求son'[x]>=2,这样才会有两个重要的点的最近公共祖先是x。那么对于一个点x的son'又会受什么影响呢?当一个点y满足son'[y]==0&&y是不重要的点那么son'[fa[y]]--。这样我们就能维护我们需要的信息了。O(mlogm)
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#define SZ(X) ((int)X.size())
#define mp make_pair
#define pb push_back
#define RALL(X) X.rbegin(),X.rend()
#define ALL(X) X.begin(),X.end()
using ll = long long ;
using ld = long double ;
const int MAXN = 1E5 + 7;
vector<int>G[MAXN];
int n;
int depth[MAXN], f[MAXN], son[MAXN], tmp[MAXN], unimp[MAXN];
void dfs(int u, int fa, int d)
{
depth[u] = d;
f[u] = fa;
for(int v : G[u]) {
if(v != fa) {
son[u] ++;
dfs(v, u, d + 1);
}
}
}
int main()
{
int T,C=0;
scanf("%d",&T);
while(T --) {
printf("Case #%d:\n",++C);
int q;
scanf("%d%d",&n,&q);
for(int i = 1;i <= n;i ++) {
son[i] = 0;
G[i].clear();
}
for(int i = 2;i <= n;i ++) {
int a, b;
scanf("%d%d",&a,&b);
G[a].pb(b);
G[b].pb(a);
}
dfs(1, 0, 1);
while(q --) {
int m;
scanf("%d",&m);
int res = n - m;
for(int i = 1;i <= m;i ++) scanf("%d",&unimp[i]);
sort(unimp+1, unimp+1+m, [](int a, int b){return depth[a] > depth[b];});
for(int i = 1;i <= m;i ++) tmp[unimp[i]] = son[unimp[i]];
for(int i = 1;i <= m;i ++) {
if(tmp[unimp[i]] >= 2) res ++;
else if(tmp[unimp[i]] == 0) {
tmp[f[unimp[i]]] --;
}
}
printf("%d\n", res);
}
}
return 0;
}
HDU5927
最新推荐文章于 2020-02-05 23:33:01 发布