Codeforces Round 915 (div2) E

发布时间 2023-12-26 16:23:52作者: weirdoX

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;
}