1. 程式人生 > >[虛樹模板] 洛谷P2495 消耗戰

[虛樹模板] 洛谷P2495 消耗戰

技術 clu mil get -- ont 模板 def clas

題意:給定樹上k個點,求切斷這些點到根路徑的最小代價。∑k <= 5e5

解:虛樹。

構建虛樹大概是這樣的:設加入點與棧頂的lca為y,比較y和棧中第二個元素的DFS序大小關系。

代碼如下:

 1 inline bool cmp(const int &a, const int &b) {
 2     return pos[a] < pos[b];
 3 }
 4 
 5 inline void build_t() {
 6     std::sort(imp + 1, imp + k + 1, cmp);
 7     TP = top = 0;
 8     stk[++top] = imp[1
]; 9 use[imp[1]] = Time; 10 E[imp[1]] = 0; 11 for(int i = 2; i <= k; i++) { 12 int x = imp[i], y = lca(x, stk[top]); 13 if(use[x] != Time) { 14 use[x] = Time; 15 E[x] = 0; 16 } 17 if(use[y] != Time) { 18 use[y] = Time;
19 E[y] = 0; 20 } 21 while(top > 1 && pos[y] <= pos[stk[top - 1]]) { 22 ADD(stk[top - 1], stk[top]); 23 top--; 24 } 25 if(stk[top] != y) { 26 ADD(y, stk[top]); 27 stk[top] = y; 28 } 29 stk[++top] = x;
30 } 31 while(top > 1) { 32 ADD(stk[top - 1], stk[top]); 33 top--; 34 } 35 RT = stk[top]; 36 return; 37 }

然後本題建虛樹跑DP就行了。註意虛樹根節點的DP初值和虛樹的邊權。

技術分享圖片
  1 #include <cstdio>
  2 #include <algorithm>
  3 
  4 typedef long long LL;
  5 const int N = 250010;
  6 const LL INF = 1e18;
  7 
  8 struct Edge {
  9     int nex, v;
 10     LL len;
 11 }edge[N << 1], EDGE[N << 1]; int tp, TP;
 12 
 13 int e[N], siz[N], stk[N], top, Time, n, fa[N][20], k, RT, num, pos[N], pw[N], now[N], imp[N], E[N], d[N], use[N];
 14 LL f[N], small[N][20];
 15 
 16 inline void ADD(int x, int y, LL z) {
 17     TP++;
 18     EDGE[TP].v = y;
 19     EDGE[TP].len = z;
 20     EDGE[TP].nex = E[x];
 21     E[x] = TP;
 22     return;
 23 }
 24 
 25 inline void add(int x, int y, LL z) {
 26     top++;
 27     edge[top].v = y;
 28     edge[top].len = z;
 29     edge[top].nex = e[x];
 30     e[x] = top;
 31     return;
 32 }
 33 
 34 void DFS_1(int x, int father) { // get fa small
 35     fa[x][0] = father;
 36     d[x] = d[father] + 1;
 37     pos[x] = ++num;
 38     for(int i = e[x]; i; i = edge[i].nex) {
 39         int y = edge[i].v;
 40         if(y == father) {
 41             continue;
 42         }
 43         small[y][0] = edge[i].len;
 44         DFS_1(y, x);
 45     }
 46     return;
 47 }
 48 
 49 inline int lca(int x, int y) {
 50     if(d[x] > d[y]) {
 51         std::swap(x, y);
 52     }
 53     int t = pw[n];
 54     while(t >= 0 && d[x] < d[y]) {
 55         if(d[fa[y][t]] >= d[x]) {
 56             y = fa[y][t];
 57         }
 58         t--;
 59     }
 60     if(x == y) {
 61         return x;
 62     }
 63     t = pw[n];
 64     while(t >= 0 && fa[x][0] != fa[y][0]) {
 65         if(fa[x][t] != fa[y][t]) {
 66             x = fa[x][t];
 67             y = fa[y][t];
 68         }
 69         t--;
 70     }
 71     return fa[x][0];
 72 }
 73 
 74 inline bool cmp(const int &a, const int &b) {
 75     return pos[a] < pos[b];
 76 }
 77 
 78 inline LL getMin(int x, int y) {
 79     LL ans = INF;
 80     int t = pw[d[y] - d[x]];
 81     while(t >= 0 && y != x) {
 82         if(d[fa[y][t]] >= d[x]) {
 83             ans = std::min(ans, small[y][t]);
 84             y = fa[y][t];
 85         }
 86         t--;
 87     }
 88     return ans;
 89 }
 90 
 91 inline void build_t() {
 92     std::sort(imp + 1, imp + k + 1, cmp);
 93     TP = top = 0;
 94     stk[++top] = imp[1];
 95     use[imp[1]] = Time;
 96     E[imp[1]] = 0;
 97     for(int i = 2; i <= k; i++) {
 98         int x = imp[i], y = lca(x, stk[top]);
 99         if(use[x] != Time) {
100             use[x] = Time;
101             E[x] = 0;
102         }
103         if(use[y] != Time) {
104             use[y] = Time;
105             E[y] = 0;
106         }
107         while(top > 1 && pos[y] <= pos[stk[top - 1]]) {
108             ADD(stk[top - 1], stk[top], getMin(stk[top - 1], stk[top]));
109             top--;
110         }
111         if(stk[top] != y) {
112             ADD(y, stk[top], getMin(y, stk[top]));
113             stk[top] = y;
114         }
115         stk[++top] = x;
116     }
117     while(top > 1) {
118         ADD(stk[top - 1], stk[top], getMin(stk[top - 1], stk[top]));
119         top--;
120     }
121     RT = stk[top];
122     return;
123 }
124 
125 void DFS(int x) {
126     siz[x] = (now[x] == Time);
127     LL temp = 0;
128     for(int i = E[x]; i; i = EDGE[i].nex) {
129         int y = EDGE[i].v;
130         f[y] = EDGE[i].len;
131         DFS(y);
132         siz[x] += siz[y];
133         if(siz[y]) {
134             temp += f[y];
135         }
136     }
137     if(now[x] != Time) {
138         f[x] = std::min(f[x], temp);
139     }
140     return;
141 }
142 
143 void out(int x) {
144     return;
145 }
146 
147 int main() {
148     scanf("%d", &n);
149     /*if(n > 100) {
150         return -1;
151     }*/
152     int x, y; LL z;
153     for(int i = 1; i < n; i++) {
154         scanf("%d%d%lld", &x, &y, &z);
155         add(x, y, z);
156         add(y, x, z);
157     }
158     // get lca min_edge
159     DFS_1(1, 0);
160     for(int i = 2; i <= n; i++) {
161         pw[i] = pw[i >> 1] + 1;
162     }
163     for(int j = 1; j <= pw[n]; j++) {
164         for(int i = 1; i <= n; i++) {
165             fa[i][j] = fa[fa[i][j - 1]][j - 1];
166             small[i][j] = std::min(small[i][j - 1], small[fa[i][j - 1]][j - 1]);
167         }
168     }
169 
170     int m;
171     scanf("%d", &m);
172     for(Time = 1; Time <= m; Time++) {
173         scanf("%d", &k);
174         //printf("\n k = %d \n", k);
175         for(int i = 1; i <= k; i++) {
176             scanf("%d", &imp[i]);
177             now[imp[i]] = Time;
178         }
179         //printf("input over \n");
180         build_t();
181         //out(RT);
182         f[RT] = getMin(1, RT);
183         DFS(RT);
184         printf("%lld\n", f[RT]);
185     }
186 
187     return 0;
188 }
AC代碼

[虛樹模板] 洛谷P2495 消耗戰