bzoj3611: [Heoi2014]大工程

题目链接

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; 
} 
posted @ 2018-06-03 10:28  zzzzx  阅读(112)  评论(2编辑  收藏  举报