Description:
1<=n,sum(k)<=1e5
题解:
首先建出虚树。
然后考虑把所有的点分为三类:
1.虚树上的点
2.虚树上边(不包括虚树点)的点和伸出去的子树
3.不属于1、2类的点
对于虚树上的点,使用树形dp求出每一个点所有子树中第1长的和第2长的。
不属于1、2类点,可以对每个点所有伸出的子树预处理深度排序后的结果,或者用multiset动态维护
最难的在于第2类点
假设虚树有一条边x,y(dep[x]<dep[y])
x的子树中除y最长是X,y的子树中除x最长是Y
知道了这个解个方程就可以确定分界点,分界点下的到x近,分界点上的到y近。
注意/2要向-∞取整(被坑的好惨啊),改:好像不用的
然后再考虑套个树链剖分,轻链和重链的第一个特殊算,对于一条连续的重链就维护除重儿子外子树最大值+=深度再取最大值,
树链剖分没有修改,所以可以预处理整条重链的答案。
复杂度:
O
(
n
l
o
g
n
)
O(n~log~n)
O(n log n)
当然不预处理也绰绰有余
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define pp printf
#define ll long long
using namespace std;
const int N = 1e5 + 5;
int n, Q, fa[N], x, y;
int fi[N], nt[N * 2], to[N * 2], tot;
void link(int x, int y) {
nt[++ tot] = fi[x], to[tot] = y, fi[x] = tot;
}
int p[N], q[N], tp;
int dep[N], siz[N], son[N], top[N];
void dg(int x) {
p[x] = ++ tp;
dep[x] = dep[fa[x]] + 1;
siz[x] = 1;
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x]) {
fa[to[i]] = x;
dg(to[i]), siz[x] += siz[to[i]];
if(siz[to[i]] > siz[son[x]]) son[x] = to[i];
}
q[x] = tp;
}
int w[N], tw, nw[N];
void dfs(int x) {
w[x] = ++ tw; nw[tw] = x;
if(son[x]) top[son[x]] = top[x], dfs(son[x]);
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x] && to[i] != son[x])
top[to[i]] = to[i], dfs(to[i]);
}
int lca(int x, int y) {
while(top[x] != top[y])
if(dep[top[x]] >= dep[top[y]])
x = fa[top[x]]; else y = fa[top[y]];
return dep[x] < dep[y] ? x : y;
}
int d[N], d0, z[N], z0, e[N], e0;
int cmp(int x, int y) {
return p[x] < p[y];
}
struct nod {
int f1, y1, f2, y2;
void zl() {
f1 = f2 = 0;
y1 = y2 = 0;
}
void gx(int f, int y) {
if(f > f1) f2 = f1, y2 = y1, f1 = f, y1 = y; else
if(f > f2) f2 = f, y2 = y;
}
void cs2() {
f1 = f2 = 1e9;
y1 = y2 = 0;
}
void gx2(int f, int y) {
if(f < f1) f2 = f1, y2 = y1, f1 = f, y1 = y; else
if(f < f2) f2 = f, y2 = y;
}
} f[N], g[N];
int md[N], sm[N];
void dd(int x) {
md[x] = 0;
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x]) {
dd(to[i]);
md[x] = max(md[x], md[to[i]] + 1);
f[x].gx(md[to[i]] + 1, to[i]);
}
}
void du(int x) {
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x]) {
sm[to[i]] = max(sm[x], f[x].y1 == to[i] ? f[x].f2 : f[x].f1) + 1;
du(to[i]);
}
}
int F[N], F1[N], F2[N];
int g1(int x, int y) { return F1[x] > F1[y] ? x : y;}
int g2(int x, int y) { return F2[x] > F2[y] ? x : y;}
int t1[N * 4], t2[N * 4];
#define i0 i + i
#define i1 i + i + 1
void bt(int i, int x, int y) {
if(x == y) {
t1[i] = t2[i] = nw[x];
return;
}
int m = x + y >> 1;
bt(i0, x, m); bt(i1, m + 1, y);
t1[i] = g1(t1[i0], t1[i1]);
t2[i] = g2(t2[i0], t2[i1]);
}
int pl, pr, px, pc;
void ft(int i, int x, int y) {
if(y < pl || x > pr) return;
if(x >= pl && y <= pr) {
px = pc == 1 ? g1(px, t1[i]) : g2(px, t2[i]);
return;
}
int m = x + y >> 1; ft(i0, x, m); ft(i1, m + 1, y);
}
int fq[N];
int qj(int x, int y) {
while(1) {
if(w[x] - w[top[x]] >= y)
return nw[w[x] - y];
y -= w[x] - w[top[x]] + 1;
x = fa[top[x]];
}
}
int la, ans;
void gg(int x, int y, int c) {
while(top[x] != top[y]) {
int z = f[x].y1 == la ? f[x].f2 : f[x].f1;
if(pc == 1) z += dep[x]; else z -= dep[x];
ans = max(ans, z + c);
pl = w[top[x]], pr = w[x] - 1; px = 0;
ft(1, 1, n);
if(pc == 1) ans = max(ans, F1[px] + c); else
ans = max(ans, F2[px] + c);
la = top[x];
x = fa[top[x]];
}
int z = f[x].y1 == la ? f[x].f2 : f[x].f1;
if(pc == 1) z += dep[x]; else z -= dep[x];
ans = max(ans, z + c);
pl = w[y], pr = w[x] - 1; px = 0;
ft(1, 1, n);
if(pc == 1) ans = max(ans, F1[px] + c); else
ans = max(ans, F2[px] + c);
}
multiset<int> s[N];
int main() {
freopen("inception.in", "r", stdin);
freopen("inception.out", "w", stdout);
scanf("%d %d", &n, &Q);
fo(i, 1, n - 1) {
scanf("%d %d", &x, &y);
link(x, y); link(y, x);
}
dg(1); top[1] = 1; dfs(1);
dd(1); du(1);
fo(i, 1, n) {
F[i] = son[i] == f[i].y1 ? f[i].f2 : f[i].f1;
F1[i] = F[i] + dep[i];
F2[i] = F[i] - dep[i];
}
fo(i, 2, n) s[fa[i]].insert(md[i]);
F[0] = F1[0] = F2[0] = -1e9;
bt(1, 1, n);
fo(ii, 1, Q) {
ans = 0;
scanf("%d", &z0);
fo(i, 1, z0) scanf("%d", &z[i]);
d0 = z0; fo(i, 1, d0) d[i] = z[i];
sort(d + 1, d + d0 + 1, cmp);
fo(i, 2, d0) d[++ d0] = lca(d[i - 1], d[i]);
sort(d + 1, d + d0 + 1, cmp);
d0 = unique(d + 1, d + d0 + 1) - (d + 1);
e0 = 0;
fo(i, 1, d0) {
#define iz(x, y) (p[x] >= p[y] && p[x] <= q[y])
while(e0 > 0 && !iz(d[i], e[e0])) e0 --;
fq[d[i]] = e[e0]; e[++ e0] = d[i];
}
//dp
fo(i, 1, d0) g[d[i]].cs2();
fo(i, 1, z0) g[z[i]].zl();
fd(i, d0, 1) {
int x = d[i];
g[fq[x]].gx2(dep[x] - dep[fq[x]] + g[x].f1, x);
}
fo(i, 1, d0) {
int x = d[i];
if(!fq[x]) continue;
int s = g[fq[x]].y1 == x ? g[fq[x]].f2 : g[fq[x]].f1;
g[x].gx2(dep[x] - dep[fq[x]] + s, fq[x]);
}
fo(i, 1, d0) {
int x = d[i], y = fq[x];
if(!y || fa[x] == y) continue;
la = x;
int X = g[x].y1 == y ? g[x].f2 : g[x].f1;
int Y = g[y].y1 == x ? g[y].f2 : g[y].f1;
X ++; Y ++;
y = qj(x, dep[x] - dep[y] - 1); x = fa[x];
int len = dep[x] - dep[y];
int D = (Y - X + len - 1);
if(D < 0) D = (D - 1) / 2; else D /= 2;
if(D > len) D = len;
if(D >= 0) {
int z = qj(x, D);
pc = 2; gg(x, z, dep[x] + X);
la = z;
}
if(D < 0) D = 0; else D ++;
if(D <= len) {
int z = fa[la];
pc = 1; gg(z, y, -dep[y] + Y);
}
}
//out of the fake tree
fo(i, 2, d0) {
int x = d[i], y = fq[x];
int z = qj(x, dep[x] - dep[y] - 1);
s[y].erase(s[y].find(md[z]));
}
fo(i, 1, d0) {
int x = d[i];
if(s[x].size()) ans = max(ans, (*s[x].rbegin()) + 1 + g[x].f1);
}
fo(i, 2, d0) {
int x = d[i], y = fq[x];
int z = qj(x, dep[x] - dep[y] - 1);
s[y].insert(md[z]);
}
//in the fake tree
fo(i, 1, d0) {
int x = d[i]; ans = max(ans, g[x].f1);
}
ans = max(ans, g[d[1]].f1 + sm[d[1]]);
pp("%d\n", ans);
}
}