Codeforces 733F Drivers Dissatisfaction
题意:有n个点,m条边,每条边有不满意度w[i],以及减小一个不满意度代价c[i],问给你s元用来减少代价,找到一个总不满意度最小的生成树,保证有解。(减少后的不满意度可以为负数)
思路:
显然所有的钱都应该用在生成树中c最小的那条边上
先求出以w[i]为权的最小生成树O(nlogn)
答案一定是在现在求出的最小生成树基础上换掉一条边 或 不变
把所有边进行替换尝试,找到换掉后的最优解。(可以只尝试c不大于mst中最小的c的边)
添加一条边后需要尝试换掉,与该边组成环后的最大权的边,
找最大权就是找新增边的两个节点到最近公共祖先的路径上的最大边
具体见代码
- const int maxn = * + ;
- struct Edge {
- int id, u, v, w, c;//从u到v权为w
- bool operator < (const Edge& rhs) const {
- if (w != rhs.w) return w < rhs.w;
- return id < rhs.id;
- }
- };
- vector<Edge> e;
- int n, m;
- int pa[maxn];
- vector<pair<int, bool> > G[maxn];
- bool vis[maxn]; //被选中的边
- int find(int x) {
- return pa[x] != x ? pa[x] = find(pa[x]) : x;
- }
- int kruskal() {
- int min_c = INF;
- for (int i = ; i <= n; i++) pa[i] = i;
- sort(e.begin(), e.end());
- for (int i = ; i < e.size(); i++) {
- int x = find(e[i].u), y = find(e[i].v);
- if (x != y) {
- vis[e[i].id] = true;
- min_c = min(min_c, e[i].c);
- G[e[i].u].push_back(mp(i, ));
- G[e[i].v].push_back(mp(i, ));
- pa[x] = y;
- }
- }
- return min_c;
- }
- const int maxlog = ;
- int fa[maxn]; // 父亲数组
- int cost[maxn]; // 和父亲的费用
- int L[maxn]; // 层次(根节点层次为0)
- struct LCA {
- int anc[maxn][maxlog]; // anc[p][i]是结点p的第2^i级父亲。anc[i][0] = fa[i]
- int maxcost[maxn][maxlog]; // maxcost[p][i]是i和anc[p][i]的路径上的最大费用
- // 预处理,根据fa和cost数组求出anc和maxcost数组
- void preprocess() {
- for(int i = ; i <= n; i++) {
- anc[i][] = fa[i]; maxcost[i][] = cost[i];
- for(int j = ; ( << j) <= n; j++) anc[i][j] = -;
- }
- for(int j = ; ( << j) <= n; j++) {
- for(int i = ; i <= n; i++) {
- if(anc[i][j-] != -) {
- int a = anc[i][j-];
- anc[i][j] = anc[a][j-];
- maxcost[i][j] = max(maxcost[i][j-], maxcost[a][j-]);
- }
- }
- }
- }
- // 求p到q的路径上的最大权
- pii query(int p, int q) {
- int tmp, power, i;
- if(L[p] < L[q]) swap(p, q); //L[p] >= L[q]
- for(power = ; ( << power) <= L[p]; power++);
- power--; //(2^power <= L[p]中的最大的)
- int ans = -INF;
- for(int i = power; i >= ; i--) {
- if (L[p] - ( << i) >= L[q]) {
- ans = max(ans, maxcost[p][i]);
- p = anc[p][i];
- }
- }
- if (p == q) return mp(ans, p); // LCA为p
- for(int i = power; i >= ; i--) {
- if(anc[p][i] != - && anc[p][i] != anc[q][i]) {
- ans = max(ans, maxcost[p][i]); p = anc[p][i];
- ans = max(ans, maxcost[q][i]); q = anc[q][i];
- }
- }
- ans = max(ans, cost[p]);
- ans = max(ans, cost[q]);
- return mp(ans, fa[p]); // LCA为fa[p](它也等于fa[q])
- }
- } lca;
- int w[maxn], c[maxn];
- int all;
- void init()
- {
- scanf("%d%d", &n, &m);
- for (int i = ; i < m; i++)
- {
- scanf("%lld", w + i);
- }
- for (int i = ; i < m; i++)
- {
- scanf("%lld", c + i);
- }
- int u, v;
- for (int i = ; i < m; i++)
- {
- scanf("%d%d", &u, &v);
- e.push_back((Edge){i, u, v, w[i], c[i]});
- }
- scanf("%d", &all);
- }
- void bfs()
- {
- queue<int> q;
- q.push();
- fa[] = ;
- L[] = ;
- cost[] = ;
- while (!q.empty())
- {
- int u = q.front(); q.pop();
- for (auto i : G[u])
- {
- int v = e[i.x].v;
- if (i.y) v = e[i.x].u;
- if (fa[u] == v)
- {
- continue;
- }
- q.push(v);
- fa[v] = u;
- L[v] = L[u] + ;
- cost[v] = e[i.x].w;
- }
- }
- }
- int find_idx(int u, int v) //找边uv的编号
- {
- if (u == -) cout << "error!" << endl;
- for (int i = ; i < G[u].size(); i++)
- {
- int to = e[G[u][i].x].v;
- if (G[u][i].y) to = e[G[u][i].x].u;
- if (to == v) return e[G[u][i].x].id;
- }
- }
- Edge find_change(const int min_c, LL& sub)
- {
- Edge ans = (Edge){-};
- for (auto i : e)
- {
- if (vis[i.id] || i.c > min_c) continue;
- LL max_wc = lca.query(i.u, i.v).x;
- LL new_sub = all / i.c - i.w + max_wc;
- if (new_sub > sub)
- {
- sub = new_sub;
- ans = i;
- }
- }
- return ans;
- }
- int find_delete(const Edge& ans)
- {
- pii father = lca.query(ans.u, ans.v);
- pii del(-, -); //删除 del
- for (int i = ans.u; i != father.y; i = fa[i])
- {
- if (cost[i] == father.x)
- {
- del = mp(i, fa[i]);
- break;
- }
- }
- if (del.x == -)
- {
- for (int i = ans.v; i != father.y; i = fa[i])
- {
- if (cost[i] == father.x)
- {
- del = mp(i, fa[i]);
- break;
- }
- }
- }
- return find_idx(del.x, del.y);
- }
- void solve()
- {
- int min_c = kruskal();
- /*
- cout << "MST:" <<endl;
- for (auto i : e)
- if (vis[i.id]) cout << i.id +1 << " ";
- cout << endl;
- */
- bfs();
- lca.preprocess();
- LL sub = all / min_c;
- Edge ans = find_change(min_c, sub);
- LL sum = ;
- for (auto i : e)
- {
- if (vis[i.id]) sum += i.w;
- }
- printf("%lld\n", sum - sub);
- if (ans.id == -)
- {
- bool flag = true;
- for (auto i : e)
- {
- if (vis[i.id])
- {
- if (flag && i.c == min_c)
- {
- printf("%d %d\n", i.id + , i.w - all / i.c);
- flag = false;
- }
- else
- printf("%d %d\n", i.id + , i.w);
- }
- }
- return;
- }
- int idx = find_delete(ans);
- for (auto i : e)
- {
- if (vis[i.id] && i.id != idx)
- {
- printf("%d %d\n", i.id + , i.w);
- }
- }
- printf("%d %d\n", ans.id + , ans.w - all/ans.c);
- }
- int main()
- {
- init();
- solve();
- return ;
- }
Codeforces 733F Drivers Dissatisfaction的更多相关文章
- 【codeforces 733F】 Drivers Dissatisfaction
http://codeforces.com/problemset/problem/733/F (题目链接) 题意 给出一张n个点的无向图,每一条变有两个特征值:${w,c}$:分别表示这条边的权值为$ ...
- Codeforces Round #378 (Div. 2) F - Drivers Dissatisfaction
F - Drivers Dissatisfaction 题目大意:给你n个点,m条边,每个边都有一个权重w,每条边也有一个c表示,消耗c元可以把这条边的权重减1,求最多消耗s元的最小生成树. 思路:因 ...
- Drivers Dissatisfaction
Drivers Dissatisfaction time limit per test 4 seconds memory limit per test 256 megabytes input stan ...
- CF733F Drivers Dissatisfaction【链剖】【最小生成树应用】
F. Drivers Dissatisfaction time limit per test 4 seconds memory limit per test 256 megabytes input s ...
- 【codeforces 733F】Drivers Dissatisfaction
[题目链接]:http://codeforces.com/problemset/problem/733/F [题意] 给你n个点m条边; 让你从中选出n-1条边; 形成一个生成树; (即让n个点都联通 ...
- Codeforces Round #378 (Div. 2)F - Drivers Dissatisfaction GNU
http://codeforces.com/contest/733/problem/F 题意:给你一些城市和一些路,每条路有不满意程度和每减少一点不满意程度的花费,给出最大花费,要求找出花费小于s的最 ...
- codeforce 378 div 2 F —— Drivers Dissatisfaction (最小生成树,LCA,倍增)
官方题解: If you choose any n - 1 roads then price of reducing overall dissatisfaction is equal to min(c ...
- Drivers Dissatisfaction 最小生成树+LCA
题意:给一张n个点m条边的连通图,每条边(ai,bi)有一个权值wi和费用ci, 表示这条边每降低1的权值需要ci的花费.现在一共有S费用可以用来降低某些边的权值 (可以降到负数),求图中的一棵权值和 ...
- 【CF733F】Drivers Dissatisfaction(最小瓶颈生成树,倍增)
题意:给出一个图,每条边有权值和花费c,每次花费c能使的权值-1.给出一个预算,求减完权值后的一个最小生成树. 思路:感谢CC大神 有这样一个结论:最佳方案里必定存在一种,预算全部花费全部分配在一条边 ...
随机推荐
- nodejs 访问mysql
安装 $ npm install mysql 简介 这个一个mysql的nodejs版本的驱动,是用JavaScript来编写的.不需要编译 这儿有个例子来示范如何使用: var mysql = re ...
- Java面向对象三大特点之封装
封装 含义:将对象的属性和行为封装起来,而将对象的属性和行为封装起来的载体是类,类通常对客户隐藏其实现细节,这就是封装的思想.封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的 ...
- 数据库 基础篇3(mysql语法)
4 数据库管理(接上篇) 4.1 查询所有数据库 mysql> show databases; +--------------------+ | Database | +-- ...
- AngularJS: 'Template for directive must have exactly one root element' when using 'th' tag in directive template
.controller('HomeController', function($scope,$location) { $scope.userName='天下大势,为我所控!'; $scope.clkU ...
- 学习swift开源项目
如果你是位iOS开发者,或者你正想进入该行业,那么Swift为你提供了一个绝佳的机会.Swift的设计非常优雅,较Obj-C更易于学习,当然也非常强大. 为了指导开发者使用Swift进行开发,苹果发布 ...
- Positive-definite kernel
Definition Let be a sequence of (complex) Hilbert spaces and be the bounded operators from Hi to Hj. ...
- 向mysql workbench中导入.sql文件
mysql workbench用的不多,前段时间装了一下,然后用了一下,感觉操作比dbdesigner4要更人性化一点.其中二个方面做了改进,让我觉得很爽. 第一,就是端口可以修改了,以前就是定死33 ...
- 关于javascript中的===和==
=是赋值符号,==是等于,===是严格等于. 对于等号两边的数值,如果类型不相同会先转换类型再比较,===则不会转换类型. 例如3和“3”在==比较下true,在===下是false, null和un ...
- CSS 选择器【详解】
转自:http://www.cnblogs.com/polk6/archive/2013/07/19/3142142.html CSS 选择器及各样式引用方式介绍 一个好的界面,是一个Web吸引人们最 ...
- iOS学习之GCD
多线程编程 线程定义:一个CPU执行的CPU命令 列一条无分叉的路径就叫线程. 多线程:执行多个不同的CPU命令 有多条路径. 线程的使用:主线程(又叫作UI线程)主要任务是处理UI事件,显示和刷新U ...