CF 903G. Yet Another Maxflow Problem

题意

In this problem you will have to deal with a very special network.

The network consists of two parts: part A and part B. Each part consists of n vertices; i-th vertex of part A is denoted as Ai, and i-th vertex of part B is denoted as Bi.

For each index i (1 ≤ i < n) there is a directed edge from vertex Ai to vertex Ai + 1, and from Bi to Bi + 1, respectively. Capacities of these edges are given in the input. Also there might be several directed edges going from part A to part B (but never from B to A).

You have to calculate the maximum flow value from A1 to Bn in this network. Capacities of edges connecting Ai to Ai + 1 might sometimes change, and you also have to maintain the maximum flow value after these changes. Apart from that, the network is fixed (there are no changes in part B, no changes of edges going from A to B, and no edge insertions or deletions).

Take a look at the example and the notes to understand the structure of the network better.

Input

The first line contains three integer numbers n, m and q (2 ≤ n, m ≤ 2·105, 0 ≤ q ≤ 2·105) — the number of vertices in each part, the number of edges going from A to B and the number of changes, respectively.

Then n - 1 lines follow, i-th line contains two integers xi and yi denoting that the edge from Ai to Ai + 1 has capacity xi and the edge from Bi to Bi + 1 has capacity yi (1 ≤ xi, yi ≤ 109).

Then m lines follow, describing the edges from A to B. Each line contains three integers x, y and z denoting an edge from Ax to By with capacity z (1 ≤ x, y ≤ n, 1 ≤ z ≤ 109). There might be multiple edges from Ax to By.

And then q lines follow, describing a sequence of changes to the network. i-th line contains two integers vi and wi, denoting that the capacity of the edge from Avi to Avi + 1 is set to wi (1 ≤ vi < n, 1 ≤ wi ≤ 109).

Output

Firstly, print the maximum flow value in the original network. Then print q integers, i-th of them must be equal to the maximum flow value after i-th change.

Example

input
4 3 2
1 2
3 4
5 6
2 2 7
1 4 8
4 3 9
1 100
2 100
output
9
14
14

分析

这题首先要想到最大流=最小割,然后只要动态维护最小割即可。
根据这个图的性质,不难发现在割掉Ai到Ai+1的边后,它后面的边和点就全部没用了。同理在割掉Bi到Bi+1的边后,它前面的边和点就全部没用了。那么最小割的形式一定是在每个点集割掉一条边或不割的代价+剩余的点之间连边的代价和的最小值。
我们可以通过线段树来动态加边并维护删掉B中每条边的代价,取个最小值就是最小割了。
修改的话,随便拿个优先队列或者set记录一下删每条边的值然后瞎搞搞就行了。

代码

#include <bits/stdc++.h>

const int N = 200005;
typedef long long ll;

int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}

struct Queue
{
    std::priority_queue<ll> q1,q2;

    ll top()
    {
        while (!q2.empty() && q2.top() == q1.top())
            q2.pop(),q1.pop();
        return q1.top();
    }

    void ins(ll x)
    {
        q1.push(x);
    }

    void del(ll x)
    {
        q2.push(x);
    }
}que;

struct Edge
{
    int to,next;
    int w;
}e[N];

int cnt;
int next[N];

void add(int x,int y,int z)
{
    e[++cnt].to = y, e[cnt].next = next[x], next[x] = cnt, e[cnt].w = z;
}

struct Tree
{
    ll tag;
    ll mn;
}t[N * 5];

int a[N],b[N];

void build(int p,int l,int r)
{
    if (l == r)
    {
        t[p].mn = b[l - 1];
        return;
    }
    int mid = (l + r) >> 1;
    build(2 * p, l, mid);
    build(2 * p + 1, mid + 1, r);
    t[p].mn = std::min(t[p * 2].mn, t[p * 2 + 1].mn);
}

void pushDown(int p,int l,int r)
{
    if (l == r || !t[p].tag)
        return;
    ll w = t[p].tag;
    t[p].tag = 0;
    t[p * 2].mn += w, t[p * 2].tag += w;
    t[p * 2 + 1].mn += w, t[p * 2 + 1].tag += w;
}

void ins(int p,int l,int r,int x,int y,int z)
{
    if (x > y)
        return ;
    pushDown(p, l, r);
    if (l == x && r == y)
    {
        t[p].mn += z;
        t[p].tag += z;
        return;
    }
    int mid = (l + r) >> 1;
    ins(p * 2, l, mid, x, std::min(y, mid), z);
    ins(p * 2 + 1, mid + 1, r, std::max(x, mid + 1), y, z);
    t[p].mn = std::min(t[p * 2].mn, t[p * 2 + 1].mn);
}

ll val[N];

int main()
{
    int n = read(), m = read(), q = read();
    for (int i = 1; i < n; i++)
        a[i] = read(), b[i] = read();
    for (int i = 1; i <= m; i++)
    {
        int x = read(), y = read(), z = read();
        add(x,y,z);
    }
    build(1,1,n);
    for (int i = 1; i <= n; i++)
    {
        for (int j = next[i]; j; j = e[j].next)
        {
            ins(1,1,n,1,e[j].to,e[j].w);
        }
        val[i] = t[1].mn;
        que.ins(-val[i] - a[i]);
    }
    printf("%I64d\n",-que.top());
    while (q--)
    {
        int x = read(), y = read();
        que.del(-val[x] - a[x]);
        a[x] = y;
        que.ins(-val[x] - a[x]);
        printf("%I64d\n",-que.top());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值