题目链接
这道题,难就难在把思维理清楚了,只要理清楚之后写起来还是比较好写的,尽管码量是真的挺大的。
我们可以给每个点去定义它是被哪个点所控制的。
(一)、求每个点是被哪个点所控制的
因为我们建树会得到一棵虚树,所以我们要知道每个点都是由哪个点所控制的,什么叫做控制?就是距离它最近的被选取的点是哪个?如果本身就是,那么就是本身。这个我们可以由两次dfs来实现,第一个dfs求的是它的子儿子中,到达它最近的点,所以是先向下跑,再回来更新;第二个dfs是把它的最近子儿子看看能不能作为别的点的最近点,也就是将父亲的最近子儿子推下去。
(二)、每一条虚链是怎样被划分的
每一条虚链上,实际上还是有点构成的,除非这条虚链的长度为1,那么上面就不会存在点了,接下去,如果虚链上有点,那么我们可以根据某个点来划分成两部分,一部分去给u点,而另一部分去给v点,于是就可以做到将这条虚链划分开来,当然有时候没法划分,就是u、v的控制点是一样的,这时候没法划分,直接整个给他们的控制点即可。
有人可能会想,如果两个点都是虚树中的非关键点怎么办(也就是乱入的lca点)?那么,也没有关系,因为我们在上一步中已经确定了控制点,算贡献利用控制点算即可。
一组样例(很显然我不是1A咯…… 2A还算是行吧):
7
1 2
1 3
3 7
2 4
4 5
5 6
1
2
6 7
ans:4 3
码量挺长的,不过有少许注释,其实理解了写起来还挺方便,就是细节注意了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 3e5 + 7;
int N, Q;
struct Build_Graph
{
int head[maxN], cnt;
struct Eddge
{
int nex, to, val;
Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), val(c) {}
}edge[maxN << 1];
inline void addEddge(int u, int v, int w)
{
edge[cnt] = Eddge(head[u], v, w);
head[u] = cnt++;
}
inline void _add(int u, int v, int w) { addEddge(u, v, w); addEddge(v, u, w); }
inline void init()
{
cnt = 0;
for(int i=1; i<=N; i++) head[i] = -1;
}
}Old, Now;
int deep[maxN], dfn[maxN], tot, root[maxN][20], LOG2[maxN], son[maxN];
inline bool cmp(int e1, int e2) { return dfn[e1] < dfn[e2]; }
void pre_dfs(int u, int fa)
{
deep[u] = deep[fa] + 1; root[u][0] = fa; dfn[u] = ++tot; son[u] = 1;
for(int i=0; i < LOG2[N]; i++) root[u][i + 1] = root[root[u][i]][i];
for(int i=Old.head[u], v; ~i; i=Old.edge[i].nex)
{
v = Old.edge[i].to;
if(v == fa) continue;
pre_dfs(v, u);
son[u] += son[v];
}
}
inline int _LCA(int u, int v)
{
if(deep[u] < deep[v]) swap(u, v);
int det = deep[u] - deep[v];
for(int i=LOG2[det]; i>=0; i--)
{
if((det >> i) & 1) u = root[u][i];
}
if(u == v) return u;
for(int i=LOG2[N]; i>=0; i--)
{
if(root[u][i] ^ root[v][i])
{
u = root[u][i];
v = root[v][i];
}
}
return root[u][0];
}
int vis[maxN] = {0}, ans[maxN] = {0}, qid[maxN], Stap[maxN], Stop;
inline void Insert(int u)
{
if(u == Stap[Stop]) return;
if(Stop <= 1) { Stap[++Stop] = u; return; }
int lca = _LCA(Stap[Stop], u);
if(lca == Stap[Stop]) { Stap[++Stop] = u; return; }
while(Stop > 1 && dfn[lca] <= dfn[Stap[Stop - 1]])
{
Now.addEddge(Stap[Stop - 1], Stap[Stop], deep[Stap[Stop]] - deep[Stap[Stop - 1]]);
Stop--;
}
if(lca ^ Stap[Stop])
{
Now.addEddge(lca, Stap[Stop], deep[Stap[Stop]] - deep[lca]);
Stap[Stop] = lca;
}
Stap[++Stop] = u;
}
pair<int, int> control_id[maxN]; //控制点
void control_dfs(int u)
{
if(vis[u]) control_id[u] = MP(u, 0);
else control_id[u] = MP(0, INF);
for(int i=Now.head[u], v; ~i; i=Now.edge[i].nex)
{
v = Now.edge[i].to;
control_dfs(v);
if(Now.edge[i].val + control_id[v].second < control_id[u].second) control_id[u] = MP(control_id[v].first, Now.edge[i].val + control_id[v].second);
else if(Now.edge[i].val + control_id[v].second == control_id[u].second && control_id[u].first > control_id[v].first) control_id[u].first = control_id[v].first;
}
}
void update_dfs(int u)
{
for(int i=Now.head[u], v; ~i; i=Now.edge[i].nex)
{
v = Now.edge[i].to;
if(control_id[u].second + Now.edge[i].val < control_id[v].second) control_id[v] = MP(control_id[u].first, control_id[u].second + Now.edge[i].val);
else if(control_id[u].second + Now.edge[i].val == control_id[v].second && control_id[u].first < control_id[v].first) control_id[v].first = control_id[u].first;
update_dfs(v);
}
}
int Up_to_Point(int u, int det) //向上det步的点
{
for(int i=LOG2[det]; i>=0; i--)
{
if((det >> i) & 1) u = root[u][i];
}
return u;
}
void query_dfs(int u)
{
int sum = 0;
for(int i=Now.head[u], v, up_len, up_id, all_len; ~i; i=Now.edge[i].nex)
{
v = Now.edge[i].to;
query_dfs(v);
sum += son[v];
if(Now.edge[i].val == 1) continue;
if(control_id[u].first == control_id[v].first) continue;
all_len = control_id[u].second + control_id[v].second + Now.edge[i].val;
if(all_len & 1) //中间偶数个点
{
up_len = (all_len - 1) / 2 - control_id[v].second;
up_id = Up_to_Point(v, up_len);
ans[vis[control_id[v].first]] += son[up_id] - son[v];
sum += son[up_id] - son[v];
}
else //中间奇数个点
{
up_len = all_len / 2 - control_id[v].second;
if(control_id[v].first > control_id[u].first) up_len--;
up_id = Up_to_Point(v, up_len);
ans[vis[control_id[v].first]] += son[up_id] - son[v];
sum += son[up_id] - son[v];
}
}
ans[vis[control_id[u].first]] += son[u] - sum;
Now.head[u] = -1;
}
inline void init()
{
tot = 0;
Old.init(); Now.init();
for(int i=1, j = 2, k = 0; i<=N; i++)
{
if(i == j) { k++; j <<= 1; }
LOG2[i] = k;
}
}
int main()
{
scanf("%d", &N);
init();
for(int i=1, u, v; i<N; i++)
{
scanf("%d%d", &u, &v);
Old._add(u, v, 1);
}
deep[0] = 0;
pre_dfs(1, 0);
scanf("%d", &Q);
int sz;
while(Q--)
{
scanf("%d", &sz);
for(int i=1; i<=sz; i++) { scanf("%d", &qid[i]); vis[qid[i]] = i; }
sort(qid + 1, qid + sz + 1, cmp);
Stap[Stop = 1] = 1;
Now.cnt = 0;
for(int i=1; i<=sz; i++) Insert(qid[i]);
while(Stop > 1)
{
Now.addEddge(Stap[Stop - 1], Stap[Stop], deep[Stap[Stop]] - deep[Stap[Stop - 1]]);
Stop --;
}
control_dfs(1);
update_dfs(1);
query_dfs(1);
for(int i=1; i<=sz; i++) printf("%d%c", ans[i], i == sz ? '\n' : ' ');
for(int i=1; i<=sz; i++) vis[qid[i]] = ans[i] = 0;
}
return 0;
}