2286: [Sdoi2011]消耗战

 

2286: [Sdoi2011]消耗战

链接

分析

  虚树练习题。

  构建虚树,在虚树上DP。

   

  跟着gxb学虚-tree。。。

代码

 

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <cmath>
  6 #include <cctype>
  7 
  8 using namespace std;
  9 
 10 const int N = 250100; 
 11 const int INF = 1e9;
 12 
 13 int head[N<<1],nxt[N<<1],to[N<<1],w[N<<1],TotE;
 14 int deth[N],val[N],siz[N],dfn[N],fa[N],son[N],bel[N],sk[N<<1],top,Time_index;
 15 int A[N];
 16 
 17 inline int read() {
 18     int x = 0,f = 1;char ch =getchar();
 19     for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-1;
 20     for (; isdigit(ch); ch=getchar()) x = x*10+ch-'0';
 21     return x * f;
 22 }
 23 bool cmp(const int &a,const int &b) {
 24     return dfn[a] < dfn[b];
 25 }
 26 void Add_edge(int u,int v,int c) {
 27     ++TotE;to[TotE] = v;w[TotE] = c;nxt[TotE] = head[u];head[u] = TotE;
 28     ++TotE;to[TotE] = u;w[TotE] = c;nxt[TotE] = head[v];head[v] = TotE;
 29 }
 30 void add_edge(int u,int v) {
 31     ++TotE;to[TotE] = v;nxt[TotE] = head[u];head[u] = TotE;
 32 }
 33 void dfs1(int u,int mn) {
 34     val[u] = mn;
 35     siz[u] = 1;
 36     for (int i=head[u]; i; i=nxt[i]) {
 37         int v = to[i];
 38         if (v==fa[u]) continue;        
 39         fa[v] = u;
 40         deth[v] = deth[u] + 1;
 41         dfs1(v,min(w[i],mn));
 42         siz[u] += siz[v];
 43         if (!son[u] || siz[v] > siz[son[u]]) son[u] = v;
 44     }
 45 }
 46 void dfs2(int u,int top) {
 47     bel[u] = top;
 48     dfn[u] = ++Time_index;
 49     if (!son[u]) return;
 50     dfs2(son[u],top);
 51     for (int i=head[u]; i; i=nxt[i]) {
 52         int v = to[i];
 53         if (v==fa[u] || v==son[u]) continue;
 54         dfs2(v,v);
 55     }
 56 }
 57 int Lca(int u,int v) {
 58     while (bel[u] != bel[v]) {
 59         if (deth[bel[u]] < deth[bel[v]]) swap(u,v);
 60         u = fa[bel[u]];
 61     }
 62     if (deth[u] < deth[v]) return u;
 63     return v;
 64 }
 65 void Insert(int p) {
 66     int x = sk[top];
 67     if (x==1) {sk[++top] = p;return ;}
 68     int lca = Lca(p,x);
 69     if (lca == x) return; // 此题构建虚树不同的是,若x==lca,不加入p。 
 70     while (lca != x) {
 71         int y = sk[--top];
 72         if (dfn[y] < dfn[lca]) {
 73             add_edge(lca,x);
 74             sk[++top] = lca;
 75             break;
 76         }
 77         add_edge(y,x);
 78         x = sk[top];
 79     }
 80     sk[++top] = p;
 81 }
 82 long long DP(int u) {
 83     if (!head[u]) return val[u];
 84     long long ans = 0;
 85     for (int i=head[u]; i; i=nxt[i]) ans += DP(to[i]);
 86     head[u] = 0;
 87     return min(ans,(long long)val[u]);    
 88 }
 89 int main() {
 90     int n = read();
 91     for (int i=1; i<n; ++i) {
 92         int u = read(),v = read(),w = read();
 93         Add_edge(u,v,w);
 94     }
 95     deth[1] = 1;
 96     dfs1(1,INF);
 97     dfs2(1,1);
 98     TotE = 0;
 99     memset(head,0,sizeof(head));
100     
101     int m = read();
102     while (m--) {
103         TotE = 0;sk[top = 1] = 1;
104         
105         int k = read();
106         for (int i=1; i<=k; ++i) A[i] = read();
107         sort(A+1,A+k+1,cmp);
108         for (int i=1; i<=k; ++i) Insert(A[i]);
109         while (--top) add_edge(sk[top],sk[top+1]);
110         
111         long long ans = 0;
112         for (int i=head[1]; i; i=nxt[i]) ans += DP(to[i]); // 单独处理1的情况,否则val[1]设为很大的longlong数,INF不够。 
113         printf("%lld\n",ans);
114         head[1] = 0;        
115     }
116     return 0;
117 }

 

posted @ 2018-06-13 21:21  MJT12044  阅读(173)  评论(0编辑  收藏  举报