bzoj3611: [Heoi2014]大工程
题目链接
题解
虚树的构造就不讲了,详见我的上一篇博客
bzoj 2286: [Sdoi2011]消耗战
然后这题我们对于每条边计算全局贡献就好了
最长、短链分别维护子树中,父节点再未更新时合并新答案就好了
define int long long
真好用 摔(╯‵□′)╯︵┻━┻
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
#define int long long
inline int read() {
int x = 0;
char c = getchar();
while(c < '0' || c > '9')c = getchar();
while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
return x;
}
const int maxn = 1000007;
struct node {
int u,v,w,next;
} edge[maxn << 1],e[maxn << 1] ;
int head[maxn],h[maxn],deep[maxn],num,num1;
inline void add_edge(int u,int v) {
edge[++ num].v = v;edge[num].next = head[u];head[u] = num;
}
inline void add(int u,int v) {if(u == v) return; e[++num1].v = v;e[num1].w = deep[v] - deep[u],e[num1].next = h[u];h[u] = num1; }
int n,dfn[maxn],dad[maxn][20],size[maxn],cnt = 0;
void dfs(int x) {
dfn[x] = ++cnt;
deep[x] = deep[dad[x][0]] + 1;
for(int i = 0;dad[x][i];++ i) dad[x][i + 1] = dad[dad[x][i]][i];
for(int i = head[x];i;i = edge[i].next) {
int v = edge[i].v;
if(v == dad[x][0]) continue;
dad[v][0] = x;
dfs(v);
}
}
int lca(int x,int y) {
if(deep[x] > deep[y])std::swap(x,y);
for(int i = 18;i >= 0;-- i) if(deep[dad[y][i]] >= deep[x]) y = dad[y][i];
if(x == y) return x ;
for(int i = 18;i >= 0;-- i) if(dad[x][i] != dad[y][i]) x = dad[x][i],y = dad[y][i];
return dad[x][0];
}
inline bool cmp(int x,int y) { return dfn[x] < dfn[y]; }
int stack[maxn];
int v[maxn];
int mn[maxn],mx[maxn];long long dp[maxn]; int ans1,ans2;
int k;
void Dp(int x) {
int tmp = 0;
size[x] = v[x]; dp[x] = 0;
mn[x] = v[x] ? 0 : INF;
mx[x] = v[x] ? 0 : -INF;
for(int i = h[x];i;i = e[i].next) {
int v = e[i].v;
Dp(v);
dp[x] += dp[v] + 1ll * (size[v] * e[i].w * (k - size[v]));
size[x] += size[v];
ans1 = std::min(ans1,mn[x] + mn[v] + e[i].w);
ans2 = std::max(ans2,mx[x] + mx[v] + e[i].w);
mn[x] = std::min(mn[v] + e[i].w,mn[x]);
mx[x] = std::max(mx[v] + e[i].w,mx[x]);
}
h[x] = 0;
}
int t[maxn];
void solve(int top = 0) {
k = read();
for(int i = 1;i <= k;++ i) t[i] = read(),v[t[i]] = 1;
std::sort(t + 1,t + k + 1,cmp);
//stack[++ top] = 1;
for(int i = 1;i <= k;++ i) {
if (!top){stack[++ top]=t[i];continue;}
int x = t[i],f = lca(stack[top],x);
if(f == stack[top]) {stack[++ top] = x; continue;}
while("tle") {
if(deep[f] >= deep[stack[top - 1]]) {
add(f,stack[top --]);
if(stack[top] != f) stack[++ top] = f;
break;
}
add(stack[top - 1],stack[top]);top --;
}
if(stack[top] != x) stack[++ top] = x;
}
while(-- top) add(stack[top],stack[top + 1]);
ans1 = INF,ans2 = -INF ;
Dp(stack[1]);
printf("%lld %lld %lld\n",dp[stack[1]],ans1,ans2);
for(int i = 1;i <= k;++ i) v[t[i]] = 0;
return ;
}
main() {
n = read();
for(int u,v,i = 1;i < n;++ i) {
u = read(),v = read();
add_edge(u,v);add_edge(v,u);
}
dfs(1);
int q = read();
for(int i = 1;i <= q;++ i)
solve();
return 0;
}