2286: [Sdoi2011]消耗战

来源:互联网 发布:贵州停车场车位软件 编辑:程序博客网 时间:2024/06/08 08:21

一道虚树模板题,虚树的写法我是写一个栈然后跑LCA的。
虚树建完之后一个树形DP就跑过去了。

#include<bits/stdc++.h>using namespace std;const int N = 250005 * 2;const int K = N;const int M = N * 3;#define int long longint st[N][32] , val[N][32] , cnt , stk[N] , top , node[N] , tot , lca ,depth[N] , dfn[N] , nodesize;int fir[N] , ne[M] , to[M] , C[M] , dp[N] , dfs_clock , out[N] , root;vector<int>G[N] , Val[N];void add(int x ,int y ,int z) {    ne[++ cnt] = fir[x]; fir[x] = cnt; to[cnt] = y; C[cnt] = z;}void link(int x ,int y,int z) {    add(x,y,z);    add(y,x,z);}#define Foreachson(i,x) for(int i = fir[x];i;i = ne[i])void dfs(int x, int f , int fe) {    depth[x] = depth[f] + 1;    st[x][0] = f;    val[x][0] = C[fe];    dfn[x] = ++ dfs_clock;    for(int i = 1;i <= 30;i ++) {        st[x][i] = st[st[x][i-1]][i-1];        val[x][i] = min(val[x][i - 1] , val[st[x][i-1]][i-1]);    }    Foreachson(i,x) {        int V = to[i];        if(V != f) {            dfs(V,x,i);        }    }    out[x] = ++ dfs_clock;}int LCA_no(int x ,int y) {    if(x == y) return x;    if(depth[x] > depth[y]) swap(x,y);    for(int i = 30;i >= 0;i --) {        if(depth[st[y][i]] >= depth[x]) y= st[y][i];    }    if(x == y) return x;    for(int i = 30;i >= 0;i --) {        if(st[y][i] != st[x][i]) {            y = st[y][i];            x = st[x][i];        }    }    return st[x][0];}int LCA_val(int x ,int y) {    if(x == y) while(1) cerr <<"Wrong Answer!"<<endl;    int res = 2e9;    if(depth[x] > depth[y]) swap(x,y);    for(int i = 30;i >= 0;i --) {        if(depth[st[y][i]] >= depth[x]) {            res = min(res,val[y][i]);            y = st[y][i];        }    }    if(x == y) return res;    for(int i = 30;i >= 0;i --) {        if(st[y][i] != st[x][i]) {            res = min(res,val[y][i]);            y = st[y][i];            res = min(res,val[x][i]);            x = st[x][i];        }    }    return min(res , min(val[x][0],val[y][0]));}bool check(int x ,int y) {    return (dfn[x] <= dfn[y] && out[x] >= out[y]);}bool cmp(int x ,int y) {    return dfn[x] < dfn[y];}int vis[N];void newnode(int x ,int t) {    if(vis[x] == t) return;    vis[x] = t;    G[x].clear();    Val[x].clear();}void newadd(int x ,int  y,int z) {    G[x].push_back(y);    Val[x].push_back(z);    G[y].push_back(x);    Val[y].push_back(z);}int List[N * 2];int in[N];void dop(int x ,int f , int t) {    dp[x] = 0;    for(int i = 0;i <(int) G[x].size();i ++) {        int V = G[x][i] , F = Val[x][i];        if(V == f) continue;        dop(V,x,t);        if(in[V] == t) dp[x] += F;        else dp[x] += min(dp[V] , F);    }}void build(int t) {    int len;    len = 0;    scanf("%lld",&tot);    List[++ len] = 1;    for(int i = 2;i <= tot + 1;i ++) scanf("%lld",&List[i]) , in[List[i]] = t;    len = tot + 1;    //果然是要sort两遍。。。     sort(List + 1, List + len + 1, cmp);    for(int i = 1;i <= tot;i ++) {        List[++ len] = LCA_no(List[i] , List[i + 1]);    }    sort(List + 1, List + len + 1, cmp);    len = unique(List + 1,List + len +1) - List - 1;    for(int i = 1;i <= len  ;i ++) {        G[List[i]].clear();        Val[List[i]].clear();    }    top = 0;    for(int i = 1;i <= len;i ++) {        while(top > 0 && !check(stk[top],List[i])) top --;        if(!top) root = List[i];        else {            newadd(stk[top] , List[i] , LCA_val(stk[top],List[i]));        }        stk[++ top] = List[i];    }    for(int i = 1;i <= len;i ++) {        dp[List[i]] = 1e18 + 666;    }    dop(1,0,t);    printf("%lld\n",dp[1]);}int n , m;signed main() {    scanf("%lld",&n);    for(int i = 1 , x, y, z;i <= n- 1;i ++) {        scanf("%lld%lld%lld",&x,&y,&z);        link(x,y,z);    }    dfs(1,0,0);    scanf("%lld",&m);    for(int i = 1;i <= m;i ++) build(i);}