题意:有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的更多相关文章

  1. 【codeforces 733F】 Drivers Dissatisfaction

    http://codeforces.com/problemset/problem/733/F (题目链接) 题意 给出一张n个点的无向图,每一条变有两个特征值:${w,c}$:分别表示这条边的权值为$ ...

  2. Codeforces Round #378 (Div. 2) F - Drivers Dissatisfaction

    F - Drivers Dissatisfaction 题目大意:给你n个点,m条边,每个边都有一个权重w,每条边也有一个c表示,消耗c元可以把这条边的权重减1,求最多消耗s元的最小生成树. 思路:因 ...

  3. Drivers Dissatisfaction

    Drivers Dissatisfaction time limit per test 4 seconds memory limit per test 256 megabytes input stan ...

  4. CF733F Drivers Dissatisfaction【链剖】【最小生成树应用】

    F. Drivers Dissatisfaction time limit per test 4 seconds memory limit per test 256 megabytes input s ...

  5. 【codeforces 733F】Drivers Dissatisfaction

    [题目链接]:http://codeforces.com/problemset/problem/733/F [题意] 给你n个点m条边; 让你从中选出n-1条边; 形成一个生成树; (即让n个点都联通 ...

  6. Codeforces Round #378 (Div. 2)F - Drivers Dissatisfaction GNU

    http://codeforces.com/contest/733/problem/F 题意:给你一些城市和一些路,每条路有不满意程度和每减少一点不满意程度的花费,给出最大花费,要求找出花费小于s的最 ...

  7. 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 ...

  8. Drivers Dissatisfaction 最小生成树+LCA

    题意:给一张n个点m条边的连通图,每条边(ai,bi)有一个权值wi和费用ci, 表示这条边每降低1的权值需要ci的花费.现在一共有S费用可以用来降低某些边的权值 (可以降到负数),求图中的一棵权值和 ...

  9. 【CF733F】Drivers Dissatisfaction(最小瓶颈生成树,倍增)

    题意:给出一个图,每条边有权值和花费c,每次花费c能使的权值-1.给出一个预算,求减完权值后的一个最小生成树. 思路:感谢CC大神 有这样一个结论:最佳方案里必定存在一种,预算全部花费全部分配在一条边 ...

随机推荐

  1. [luogu2982][USACO10FEB]慢下来Slowing down(树状数组+dfs序)

    题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows conveniently numbered 1..N mov ...

  2. mac 激活Ultra Edit16

    一.文本编辑器UltraEdit 参照Ultra Edit16.10 Mac 破解下载,或者官方下载 Ultra Edit16即可 printf of=/Applications/UltraEdit. ...

  3. zoj3228Searching the String(ac自动机)

    链接 这个题把病毒分为了两种,一种包含可以覆盖,另一种不可以,需要分别求出包含他们的个数,可以把两种都建在一颗tire树上,在最后求得时候判断一下当前节点是属于哪种字符串,如果是不包含的需要判断一下p ...

  4. Shell 语法之函数

    函数是被赋予名称的脚本代码块,可以在代码的任意位置重用.每当需要在脚本中使用这样的代码块时,只需引用该代码块被赋予的函数名称. 创建函数 格式 function name { commands } n ...

  5. 基于注解的Spring AOP的配置和使用--转载

    AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...

  6. Android开发之各个语言

    Android开发之各个语言 1.进行源码开发遇到一个最基础的问题就是各个语言下的字串翻译,所以我们必须得清楚res文件夹下各个资源文件夹 2.如图:

  7. MVC 与 webform比较

    来自:http://www.cnblogs.com/xiaozhi_5638/p/4019065.html ASP.NET Webforms Behind Code的好处和存在的问题 ASP.NET ...

  8. C#窗体 WinForm 文件操作

    文件及文件夹操作 C/S:WinForm可以操作客户端文件 Client ServerB/S:浏览器服务 Brower Server 命名空间:using system .IO; 1. File类:文 ...

  9. ListView.DragEnter触发不了

    经过千百度的搜索之后,终于找到了一点线索,原文是:https://msdn.microsoft.com/en-us/magazine/mt185571.aspx 有能力的可以参阅原文,想省事的可以等待 ...

  10. java_easyui体系之DataGrid(3)[转]

    一:简介 在2的基础上实现增删改.增.改都是通过行编辑来实现的.具体业务逻辑: 1. 增加一条记录的时候: a) 在datagrid表格最前端增加一行(当然也可在指定位置增加.)增加的行的字段必须与要 ...