题意:有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. 关于Dagger 2 的使用方式

    什么是Dagger2 Dagger是为Android和Java平台提供的一个完全静态的,在编译时进行依赖注入的框架,原来是由Square公司维护,现在由Google维护. 我们知道Dagger是一个依 ...

  2. 基于线程池和连接池的Http请求

    背景:最新项目需求调用http接口,所以打算使用最新的httpClient客户端写一个工具类,写好了以后在实际应用过程中遇到了一些问题,因为数据量还算 大,每次处理大概要处理600-700次请求,平均 ...

  3. openfire源码修改聊天消息发送内容

    /** * $RCSfile: MessageRouter.java,v $ * $Revision: 3007 $ * $Date: 2005-10-31 13:29:25 -0300 (Mon, ...

  4. Composite模式

    1 意图:将对象组成树形结构,以表示“部分——整体”的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 2 动机:同意处理图元对象和包含图元的容器对象.Composite通过 ...

  5. CSS实现垂直居中

    Hack技术就可以啊!所以在这里我还要啰嗦两句,CSS中的确是有vertical-align属性,但是它只对(X)HTML元素中拥有valign特性的元素才生效,例如表格元素中的<td>. ...

  6. JavaWeb基础: 获取资源文件

    Web工程在编译构建完毕以后,需要部署到Tomcat上运行,资源的硬盘路径也会随着改变.要想对资源文件进行读写操作需要获取其硬盘地址,在Web工程中通常通过ServletContext/ClassLo ...

  7. junit高级篇(参数化、打包测试)-实例代码

    工程目录: 参数化测试,SquareTest.java: import static org.junit.Assert.*; import java.util.Arrays; import java. ...

  8. C# checkboxlist的使用

    最近做项目,需要用到checklistbox这一控件,由于对这一控件并不是很熟悉,导致在此浪费了一点时间. http://www.cnblogs.com/hongfei/archive/2012/12 ...

  9. 非常简单的XML解析(SAX解析、pull解析)

    这里只是把解析的数据当日志打出来了 非常简单的xml解析方式 package com.example.demo.service; import java.io.IOException; import ...

  10. Visual Studio 2015 社区版.专业版.企业版[含安装密钥Pro&Ent]

    社区版(Visual Studio Community 2015)可供非企业或开源开发者们免费访问: 在线安装exe:http://download.microsoft.com/download/B/ ...