Codeforces 903G Yet Another Maxflow Problem - 线段树
题目传送门
题目大意
给定一个网络。网络分为$A$,$B$两个部分,每边各有$n$个点。对于$A_{i} \ (1\leqslant i < n)$会向$A_{i + 1}$连一条容量为$x_{i}$的有向边,对于$B_{i} \ (1\leqslant i < n)$会向$B_{i + 1}$连一条容量为$y_{i}$的有向边。$A$和$B$之间有$m$条边,起点为$A_{u_{i}}$,终点为$B_{v_{i}}$,容量为$w_{i}$的有向边。要求支持多次修改边的容量,询问$A_{1}$到$B_{n}$的最大流。
看起来不会退流的样子,所以应该可以用数据结构乱搞搞就能做出来。于是我想了很久但仍然不会。
因为最大流的流量等于最小割的容量,所以最大流不好做的时候考虑最小割。
直接考虑最小割的求解变成了最大流,这样没有用。考虑放宽一下约束条件,找一下怎样的割集是较优的。
一些显而易见的结论:
- 假如在$A$中,割掉$A_{x}$和$A_{x + 1}$之间的有向边,那么割掉$A_{y} \ (y > x)$与$A_{y + 1}$之间的有向边是没有意义的。
- 假如在$B$中,割掉$B_{x}$和$B_{x + 1}$之间的有向边,那么割掉$B_{y} \ (y < x)$与$B_{y + 1}$之间的有向边是没有意义的。
因此,在$A, B$中至多有一条边属于割集。
假设在$A$中被割掉的边是$(A_{x}, A_{x + 1})$,在$B$中被割掉的边是$B_{y}, B_{y + 1}$,那么任意$(A_{u}, B_{v}) \ (u \leqslant x \wedge v > y)$都是属于这个割集的。
因此,割的大小可以看做三部分:在$A$中的割集大小,在$B$中的割集大小,在$A, B$间的割集大小。
由于后两部分不会改变,考虑计算出它们。
考虑在$A$中从小到大枚举$A_{x}$,表示割掉$A_{x}$和$A_{x + 1}$之间的边,如果$x = n$表示不存在这条边。
那么下面要做的事情是在$B$中找到一个最优决策点$y$,使得后两部分的和最小。
对于每加入一条在$A,B$间的边,对答案造成的影响是连续的一段。
所以我们只需要写一个支持区间加,求$[1, n]$的最小值的线段树就好了。
到此,我们完美解决这道题了吗?
不,还剩下合并两部分的答案。这个可以用一个可删堆来维护。
时间复杂度$O((n + m + q)\log n)$。
Code
/**
* Codeforces
* Problem#903G
* Accepted
* Time: 451ms
* Memory: 31200k
*/
#include <bits/stdc++.h>
#ifdef WIN32
#define Auto "%I64d"
#else
#define Auto "%lld"
#endif
using namespace std; #define ll long long typedef class SegTreeNode {
public:
ll minv, lazy;
SegTreeNode *l, *r; SegTreeNode():minv(), lazy(), l(NULL), r(NULL) { } void pushUp() {
minv = min(l->minv, r->minv);
} void pushDown() {
l->minv += lazy, r->minv += lazy;
l->lazy += lazy, r->lazy += lazy;
lazy = ;
}
}SegTreeNode; #define Limit 500000 SegTreeNode pool[Limit];
SegTreeNode* top = pool; SegTreeNode* newnode() {
return top++;
} typedef class SegTree {
public:
SegTreeNode* rt; SegTree() { }
SegTree(int n, int* ar) {
build(rt, , n, ar);
} void build(SegTreeNode*& p, int l, int r, int *ar) {
p = newnode();
if (l == r) {
p->minv = ar[l];
return;
}
int mid = (l + r) >> ;
build(p->l, l, mid, ar);
build(p->r, mid + , r, ar);
p->pushUp();
} void update(SegTreeNode*& p, int l, int r, int ql, int qr, int val) {
if (l == ql && r == qr) {
p->minv += val, p->lazy += val;
return;
}
if (p->lazy) p->pushDown();
int mid = (l + r) >> ;
if (qr <= mid)
update(p->l, l, mid, ql, qr, val);
else if (ql > mid)
update(p->r, mid + , r, ql, qr, val);
else {
update(p->l, l, mid, ql, mid, val);
update(p->r, mid + , r, mid + , qr, val);
}
p->pushUp();
}
}SegTree; #define pii pair<int, int> typedef class Heap {
public:
priority_queue<ll> que;
priority_queue<ll> del; Heap() { } void insert(ll x) {
que.push(-x);
} void remove(ll x) {
del.push(-x);
} ll top() {
while (!que.empty() && !del.empty() && que.top() == del.top())
que.pop(), del.pop();
return -que.top();
}
}Heap; int n, m, q;
int *cs1, *cs2;
vector<pii> *g;
Heap hp;
SegTree st; inline void init() {
scanf("%d%d%d", &n, &m, &q);
cs1 = new int[(n + )];
cs2 = new int[(n + )];
g = new vector<pii>[(n + )];
cs1[n] = , cs2[] = ;
for (int i = ; i < n; i++)
scanf("%d%d", cs1 + i, cs2 + i + );
for (int i = , u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
g[u].push_back(pii(v, w));
}
} ll *olds;
inline void solve() {
olds = new ll[(n + )];
st = SegTree(n, cs2);
for (int i = ; i <= n; i++) {
for (int j = ; j < (signed) g[i].size(); j++)
st.update(st.rt, , n, , g[i][j].first, g[i][j].second);
hp.insert(olds[i] = cs1[i] + st.rt->minv);
// cerr << olds[i] << endl;
}
printf(Auto"\n", hp.top());
int p, nw;
while (q--) {
scanf("%d%d", &p, &nw);
hp.remove(olds[p]);
olds[p] = olds[p] - cs1[p] + nw, cs1[p] = nw;
hp.insert(olds[p]);
printf(Auto"\n", hp.top());
}
} int main() {
init();
solve();
return ;
}
Codeforces 903G Yet Another Maxflow Problem - 线段树的更多相关文章
- 【CF903G】Yet Another Maxflow Problem 线段树
[CF903G]Yet Another Maxflow Problem 题意:一张图分为两部分,左边有n个点A,右边有m个点B,所有Ai->Ai+1有边,所有Bi->Bi+1有边,某些Ai ...
- codeforces 1217E E. Sum Queries? (线段树
codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...
- [Codeforces 266E]More Queries to Array...(线段树+二项式定理)
[Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...
- [Codeforces 280D]k-Maximum Subsequence Sum(线段树)
[Codeforces 280D]k-Maximum Subsequence Sum(线段树) 题面 给出一个序列,序列里面的数有正有负,有两种操作 1.单点修改 2.区间查询,在区间中选出至多k个不 ...
- Codeforces 1089K - King Kog's Reception - [线段树][2018-2019 ICPC, NEERC, Northern Eurasia Finals Problem K]
题目链接:https://codeforces.com/contest/1089/problem/K time limit per test: 2 seconds memory limit per t ...
- Codeforces 803G Periodic RMQ Problem 线段树
Periodic RMQ Problem 动态开点线段树直接搞, 我把它分成两部分, 一部分是原来树上的, 一部分是后来染上去的,两个部分取最小值. 感觉有点难写.. #include<bits ...
- Codeforces 444 C. DZY Loves Colors (线段树+剪枝)
题目链接:http://codeforces.com/contest/444/problem/C 给定一个长度为n的序列,初始时ai=i,vali=0(1≤i≤n).有两种操作: 将区间[L,R]的值 ...
- Codeforces Gym 100513F F. Ilya Muromets 线段树
F. Ilya Muromets Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100513/probl ...
- Codeforces 834D The Bakery【dp+线段树维护+lazy】
D. The Bakery time limit per test:2.5 seconds memory limit per test:256 megabytes input:standard inp ...
随机推荐
- cocos JS for循环让精灵从屏幕中间往两边排列散开
//this.ShowImg[i] 需要排列什么就push加进数组里面,一个for循环计算即可 var size = this.ShowImg.length;var count = size; for ...
- mysql的in和not in的用法(特别注意not in结果集中不能有null)
1. not in的结果集中出现null则查询结果为null; 例如下面sql中,含有list中null值,无法正确查询结果: SELECT COUNT(name) FROM CVE WHERE na ...
- web.xml文件的简单说明
在javaEE提供的tutorial中的hello1中的web.xml文件写到: <?xml version="1.0" encoding="UTF-8" ...
- Git安装及创建版本库
一.在Windows上安装Git 1.虽然用于开发的系统最好是用Mac或者Linux,但绝大多数新人都是用Windows进行开发.Windows系统上也有提供了Git(Windows版),下载地址:h ...
- 纯HTML和CSS实现点击切换
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- WIN32窗口类风格和窗口风格(备查询)
一.WNDCLASS typedef struct { UINT cbSize //这个结构体的长度,一般用sizeof(WNDCLASSEX)设置 UINT style //窗口式样 WNDPROC ...
- html5-css边框全
/*div{ width: 500px; height: 300px; background: rgb(122,30,60); border: 10px solid black ...
- Shell 脚本编程基础
通过本文记录学习Linux Shell的一些笔记思考和总结,以加强记忆和理解.主要学习参考资料有: 1.<鸟哥的Linux私房菜-基础篇>第四版 2.菜鸟教程——Linux教程 3.ear ...
- margin、padding、border区分
margin 是设置两个标签的间隔,也就是距离: padding 这个是比如一个p标签,它是100px*100px,我们使用的时候p标签的文字是贴着p标签的最左侧的,想要它的文字距离边界远一点,好看一 ...
- sudo: apt-get: command not found
apt-get是debian(Ubuntu)才有的包管理器,而在Apple 的OS X系统中是没有的. brew(全称Homebrew)是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或 ...