Codeforces Round 915 (div2) E
E. Tree Queries
[题目链接](https://codeforces.com/contest/1904/problem/EProblem - E - Codeforces)
题意概括:
给定一棵大小为 \(n\) 的树,回答如下询问,询问之间相互独立:
- 给定一个点 \(x\) 与 \(k\) 个点 \(a_i\),求出从 \(x\) 出发不经过任何一个 \(a_i\) 的最长简单路径长度。
\(n,\sum k\le 2\times 10^5\)。
translated by cnyz.
重点思想:
一个点的子树一定是 dfn 上一段区间,用线段树对 dfn 序的深度序列维护,边 dfs 边左类似于“换根”的操作,在线段树上实时维护,对于询问讨论是否是当前点的父亲,进行做出改变。
标程:
#include <bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for (int i = (l); i <= (r); i++)
#define per(i,r,l) for (int i = (r); i >= (l); i--)
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define maxn(a, b) a = max(a, b)
#define minn(a, b) a = min(a, b)
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const ll mod = 998244353;
mt19937 gen(114514);
ll rp(ll a,ll b) {ll res=1%mod;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int inf = 1611243;
template <class T>
struct segtree {
#define ls id + id
#define rs id + id + 1
int size;
vector<T> mx, lz;
void init(int n) {
size = n;
mx.clear(); lz.clear();
mx.resize(n<<2);
lz.resize(n<<2);
}
void pushdown(int id) {
if (lz[id]) {
mx[ls] += lz[id];
mx[rs] += lz[id];
lz[ls] += lz[id];
lz[rs] += lz[id];
lz[id] = 0;
}
}
void change(int id, int l, int r, int x, int y, T v) {
if (x <= l && r <= y) {
mx[id] += v;
lz[id] += v;
return;
}
pushdown(id);
int mid = (l + r) >> 1;
if (x <= mid) change(ls, l, mid, x, y, v);
if (y > mid) change(rs, mid + 1, r, x, y, v);
mx[id] = max(mx[ls], mx[rs]);
}
T query(int id, int l, int r, int x, int y) {
if (x <= l && r <= y)
return mx[id];
pushdown(id);
int mid = (l + r) >> 1;
T res = 0;
if (x <= mid) res += query(ls, l, mid, x, y);
if (y > mid) res += query(rs, mid + 1, r, x, y);
return res;
}
T query(int l, int r) {
assert(l <= r);
return query(1, 1, size, l, r);
}
void change(int l, int r, T v) {
if (l > r) return ;
return change(1, 1, size, l, r, v);
}
};
segtree<ll> t;
const int N = 200010;
int n, tim;
int ans[N], dfn[N], sz[N], go[N];
VI e[N], no[N], qe[N];
void dfs(int u, int fa, int dep) {
dfn[u] = ++tim;
sz[u] = 1;
t.change(tim, tim, dep);
for (auto v : e[u]) {
if (v == fa) continue;
dfs(v, u, dep + 1);
sz[u] += sz[v];
}
}
set<int> stk;
void getans(int u, int fa) {
stk.insert(u);
for (auto v : e[u]) {
if (v == fa) continue;
t.change(dfn[v], dfn[v] + sz[v] - 1, -1);
t.change(1, dfn[v] - 1, 1);
t.change(dfn[v] + sz[v], n, 1);
go[u] = v;
getans(v, u);
t.change(dfn[v], dfn[v] + sz[v] - 1, 1);
t.change(1, dfn[v] - 1, -1);
t.change(dfn[v] + sz[v], n, -1);
}
for (auto id : qe[u]) {
for (auto x : no[id]) {
if (stk.count(x)) {
t.change(1, dfn[go[x]] - 1, -inf);
t.change(dfn[go[x]] + sz[go[x]], n, -inf);
} else {
t.change(dfn[x], dfn[x] + sz[x] - 1, -inf);
}
}
ans[id] = t.mx[1];
for (auto x : no[id]) {
if (stk.count(x)) {
t.change(1, dfn[go[x]] - 1, inf);
t.change(dfn[go[x]] + sz[go[x]], n, inf);
} else {
t.change(dfn[x], dfn[x] + sz[x] - 1, inf);
}
}
}
stk.erase(u);
}
int main() {
int q;
scanf("%d%d", &n, &q);
t.init(n);
rep(i,2,n) {
int u, v;
scanf("%d%d", &u, &v);
e[u].pb(v);
e[v].pb(u);
}
VI id(n + 1);
dfs(1, 0, 0);
rep(i,1,n) id[dfn[i]] = i;
rep(i,1,q) {
int k, x;
scanf("%d%d", &x, &k);
no[i].resize(k);
qe[x].pb(i);
for (auto &x : no[i]) scanf("%d", &x);
}
getans(1, 0);
rep(i,1,q) {
printf("%d\n", ans[i]);
}
return 0;
}