博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[虚树模板] 洛谷P2495 消耗战
阅读量:6248 次
发布时间:2019-06-22

本文共 6082 字,大约阅读时间需要 20 分钟。

[update]

好像有个东西叫笛卡尔树,好像是这样建的.....

 

inline void build_d() {    stk[top = 1] = 1;    for(int i = 2; i <= n; i++) {        while(top && val[stk[top]] <= val[i]) {            ls[i] = stk[top];            top--;        }        if(ls[i]) {            fa[ls[i]] = i;        }        if(top) {            fa[i] = stk[top];            rs[stk[top]] = i;        }        stk[++top] = i;    }    RT = stk[1];    return;}

 

 

 

题意:给定树上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 
2 #include
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_edge159 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代码

 

转载于:https://www.cnblogs.com/huyufeifei/p/10404454.html

你可能感兴趣的文章
如何验证cname,MX,spf记录是否生效?
查看>>
Centos系统mysql 忘记root用户的密码
查看>>
uva:10700 - Camel trading(贪婪)
查看>>
开启CURL扩展,让服务器支持PHP curl函数(远程采集)
查看>>
随笔1
查看>>
OpenStack Summit Paris 会议记录 - 11-05-2014
查看>>
asp.net 的page 基类页面 做一些判断 可以定义一个基类页面 继承Page类 然后重写OnPreLoad事件...
查看>>
解析Javascript事件冒泡机制
查看>>
linux 下一个 jira-6.3.6 组态 皴 翻译 迁移数据库
查看>>
frequentism-and-bayesianism-chs-iv
查看>>
The Unique MST (判断是否存在多个最小生成树)
查看>>
ZOJ 2319 Beatuiful People(单调递增序列的变形)
查看>>
大型网站技术架构(1)【转】
查看>>
centos7 install 安装mysql
查看>>
C++11在时空性能方面的改进
查看>>
Android ListView 单条刷新方法实践及原理解析
查看>>
BZOJ3779 : 重组病毒
查看>>
tableView 短剪线离开15像素问题
查看>>
PHPStorm+PHP5.6+WIN7+IIS7
查看>>
Neo4j集群环境建设
查看>>