[虚树模板] 洛谷P2495 消耗战
[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 <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代码
转载于:https://www.cnblogs.com/huyufeifei/p/10404454.html
[虚树模板] 洛谷P2495 消耗战相关推荐
- 洛谷 P2495 消耗战(虚树)
题目链接 题意 给你个以 111 为根节点的树,树有边权 www (割断此边),多组询问每次询问给你 mmm 个点,求割断边最小花费使得 111 到这些点都不连通. 思路 询问如果组数少可以直接 O( ...
- 字典树模板+洛谷P2580 于是他错误的点名开始了
题目: 题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次,然后正好被路过的校长发现了然后就是一顿欧拉欧拉欧拉(详情请见已结束比赛 CON ...
- 洛谷P2495 [SDOI2011]消耗战(虚树dp)
P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...
- 洛谷 P2495 [SDOI2011]消耗战 虚树
题目描述 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知 ...
- 洛谷P2495 [SDOI2011]消耗战 | 一个典型的可以搞懂虚树的例题
题目链接 题目大意: 给出一棵树,之后对这棵树进行q次询问,每次询问一个点集,给出使得这些点集中的点都不能直接或者间接的与1相连,需要删边的最小代价(边的代价在给树的时候给出),,点集不包含1,点集总 ...
- 虚树学习笔记(洛谷2495 消耗战)
题目链接 因为辣鸡csdn,导致之前快写好的博客没了 QWQ悲伤逆流成河qwqqq 首先虚树,这个东西,我感觉是一种思想,或者是方法,而并不是一个数据结构什么的. 他主要是用来解决:给出一棵树,每次询 ...
- 洛谷 P2495 [SDOI2011]消耗战 题解
题目链接 题目描述: 给你一个有边权的树,若干次询问,每次询问包含一个不含点111的kkk个点的点集,求点111与这些点都不连通的最小代价(删除一些边,代价是他们的权值和). 解题思路: 首先考虑如果 ...
- 洛谷 P2495 [SDOI2011]消耗战
题目描述 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知 ...
- 【模板】线段树 2 洛谷P3373
题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一行包含三个整数 n,m,pn,m,p,分别表示该数 ...
- 支配树(洛谷-P5180)
题目描述 给定一张有向图,求从1号点出发,每个点能支配的点的个数(包括自己) 输入输出格式 输入格式: 第一行两个正整数n,mn,m,表示点数和边数 接下来mm行,每行输入两个整数u,vu,v,表示有 ...
最新文章
- 面试官:Java反射是什么?我回答不上来!
- 关于数据库插入中文乱码问题
- Jdk1.8新特性(二)——lambda表达式(参数列表)-{}和函数式接口@FunctionalInterface
- 这两天做项目出现的几个问题
- 清华大学-美团数字生活联合研究院成立
- jQuery模板和数据绑定
- C++编写程序:输入三角形的三边,判断三角形的类型。
- 关于搜索引擎原理的详细解读
- soapui使用教程1-基本使用和录制
- 如何监控Tuxedo中间件?Oralce TUXEDO监控方案
- 如何成为一名机器学习算法工程师?
- Excel ----- 身份证自动判断男女 公式
- DMA小区漏损治理之武林秘籍
- Unix/Linux存在之必然性
- Android Remote Service
- UICC 之 USIM 详解全系列——UICC基础知识介绍
- 办公软件excel表格_Office 办公软件教程丨Word,Excel,PPT
- Vue2积分商城PC端项目(六)
- web前端学习第一周总结
- Python实战案例,pywifi模块,Python暴力破译附近局域网WiFi密码