卧薪尝胆,厚积薄发。
Yet Another Maxflow Problem
Date: Wed Jul 11 18:46:27 CST 2018
In Category:
NoCategory
Description:
给一个
$2\times n$
个节点的图,其中
$n$
个在左边,称为
$A$
,另外
$n$
个在右边,称为
$B$
,每个
$A_i,B_i$
向
$A_{i+1},B_{i+1}$
连边,边有不同权值,
$A$
和
$B$
之间有一些边,支持修改
$A_i$
到
$A_{i+1}$
的边,多次询问
$A_1$
到
$B_n$
的最大流。
$n,m,q\le 200000$
Solution:
首先肯定不可能真求最大流,由最大流
$=$
最小割得只要找到一个权值最小的割集使得删掉这些边后
$A_1$
和
$B_n$
不连通即可,发现一定是在
$A$
和
$B$
中各割掉一条边,并割掉从
$A_g$
之前的点出发连向
$B_g$
之后的点的边,发现只会对
$A$
修改,所以和每个
$A_k$
对应的
$B_k$
永远不变,考虑先提前把它求出来,依次考虑
$A$
中的所有点
$A_i$
并割掉边
$A_i\to A_{i+1}$
,发现
$A$
每向后挪一个点,从
$A_i$
出发的边必须被割掉。设这条边为
$A_i\to B_j$
,那么所有
$B_j$
之前的点
$B_x$
要想作为最终和
$A_i$
一同割掉的边,就必须把
$A_i\to B_j$
割掉,于是
$B$
的一个前缀需要加上这条边边权,区间加,区间取
$min$
用线段树第
$i$
个位置维护割掉边
$B_{i-1}\to B_i$
的花费(第
$1$
个位置代表,
$B$
中一个都不割),
$A$
一个一个往后走,每次加入从
$A_i$
出发的边即可。
最后把所有
$A$
放入一个可删堆中,修改直接删除
$+$
插入即可。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
int n,m,q;
#define MAXN 200010
#define INF 0x3f3f3f3f3f3f3f3f
int a[MAXN],b[MAXN];
struct edge
{
int to,nxt,f;
}e[MAXN];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b,int c)
{
++edgenum;e[edgenum].to = b;e[edgenum].f = c;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
#define mid ((l + r) >> 1)
struct node
{
int lc,rc;
long long minv,tag;
node(){lc = rc = 0;minv = tag = 0ll;}
}t[MAXN << 1];
int ptr = 0;
int newnode(){return ++ptr;}
int root;
void pushup(int rt)
{
t[rt].minv = min(t[t[rt].lc].minv,t[t[rt].rc].minv);
return;
}
void build(int &rt,int l,int r)
{
rt = newnode();
if(l == r)
{
t[rt].minv = (long long)b[l];
return;
}
build(t[rt].lc,l,mid);
build(t[rt].rc,mid + 1,r);
pushup(rt);
return;
}
void pushdown(int rt)
{
t[t[rt].lc].tag += t[rt].tag;
t[t[rt].rc].tag += t[rt].tag;
t[t[rt].lc].minv += t[rt].tag;
t[t[rt].rc].minv += t[rt].tag;
t[rt].tag = 0;
return;
}
void add(int rt,int L,int R,int k,int l,int r)
{
if(L > R)return;
if(L <= l && r <= R)
{
t[rt].tag += (long long)k;
t[rt].minv += (long long)k;
return;
}
pushdown(rt);
if(L <= mid)add(t[rt].lc,L,R,k,l,mid);
if(R > mid)add(t[rt].rc,L,R,k,mid + 1,r);
pushup(rt);
return;
}
long long query(int rt,int L,int R,int l,int r)
{
if(L <= l && r <= R)return t[rt].minv;
long long res = INF;
pushdown(rt);
if(L <= mid)res = min(res,query(t[rt].lc,L,R,l,mid));
if(R > mid)res = min(res,query(t[rt].rc,L,R,mid + 1,r));
return res;
}
long long res[MAXN];
typedef long long ll;
struct heap
{
priority_queue<ll,vector<ll>,greater<ll> > add;
priority_queue<ll,vector<ll>,greater<ll> > del;
void init()
{
while(!add.empty())add.pop();
while(!del.empty())del.pop();
return;
}
void insert(ll k)
{
add.push(k);
return;
}
void remove(ll k)
{
del.push(k);
return;
}
ll top()
{
while(!del.empty() && del.top() == add.top())
{
del.pop();add.pop();
}
return add.top();
}
}h;
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i <= n - 1;++i)
scanf("%d%d",&a[i],&b[i + 1]);
int x,y,z;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
build(root,1,n);
for(int k = 1;k <= n;++k)
{
for(int i = lin[k];i != 0;i = e[i].nxt)
{
add(root,1,e[i].to,e[i].f,1,n);
}
res[k] = query(root,1,n,1,n) + a[k];
h.insert(res[k]);
}
printf("%d\n",h.top());
for(int i = 1;i <= q;++i)
{
scanf("%d%d",&x,&y);
h.remove(res[x]);
res[x] -= a[x];
a[x] = y;
res[x] += a[x];
h.insert(res[x]);
printf("%I64d\n",h.top());
}
return 0;
}
In tag:
数据结构-线段树
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡