• 【CF903G】Yet Another Maxflow Problem 线段树


    【CF903G】Yet Another Maxflow Problem

    题意:一张图分为两部分,左边有n个点A,右边有m个点B,所有Ai->Ai+1有边,所有Bi->Bi+1有边,某些Ai->Bj有边,每条边都有一定的容量。

    先要求你支持两种操作:

    1.修改某条Ai->Ai+1的边的容量
    2.询问从A1到Bm的最大流

    n,m<=100000,流量<=10^9

    题解:很有思维含量的题。

    首先,我们把求最大流变成求最小割。容易发现,我们最多只会割一条Ai->Ai+1的边和一条Bi->Bi+1的边。

    假设我们割掉了Ai->Ai+1的边,如果右边割掉的是Bj->Bj+1的边,那么我们还要割掉所有Ax->By的边(x<=i,y>j)。我们可以先预处理出对于每个i,最优的j是哪个。只需要从n到1枚举每个i,然后将从i连出去的边一条一条加进去,并用线段树维护区间加,全局最值即可。

    由于每次只修改A的值,所以每个i选择的j是不变的,所以用堆维护一下最大值即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <vector>
    #define lson x<<1
    #define rson x<<1|1
    using namespace std;
    const int maxn=200010;
    typedef long long ll;
    ll s[maxn<<2],tag[maxn<<2],f[maxn],A[maxn],B[maxn];
    vector<int> C[maxn],D[maxn];
    vector<int>::iterator ci,di;
    int n,m,q;
    struct heap
    {
    	priority_queue<ll,vector<ll>,greater<ll> > p1,p2;
    	inline void erase(ll x) {p2.push(x);}
    	inline void push(ll x) {p1.push(x);}
    	inline ll top()
    	{
    		while(!p2.empty()&&p1.top()==p2.top())	p1.pop(),p2.pop();
    		return p1.top();
    	}
    }p;
    void build(int l,int r,int x)
    {
    	if(l==r)
    	{
    		s[x]=B[l];
    		return ;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,lson),build(mid+1,r,rson);
    	s[x]=min(s[lson],s[rson]);
    }
    void updata(int l,int r,int x,int a,int b,int c)
    {
    	if(a<=l&&r<=b)
    	{
    		s[x]+=c,tag[x]+=c;
    		return ;
    	}
    	if(tag[x])	s[lson]+=tag[x],s[rson]+=tag[x],tag[lson]+=tag[x],tag[rson]+=tag[x],tag[x]=0;
    	int mid=(l+r)>>1;
    	if(a<=mid)	updata(l,mid,lson,a,b,c);
    	if(b>mid)	updata(mid+1,r,rson,a,b,c);
    	s[x]=min(s[lson],s[rson]);
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),m=rd(),q=rd();
    	int i,a;
    	for(i=1;i<n;i++)	A[i]=rd(),B[i+1]=rd();
    	for(i=1;i<=m;i++)	a=rd(),C[a].push_back(rd()),D[a].push_back(rd());
    	build(1,n,1);
    	for(i=1;i<=n;i++)
    	{
    		for(ci=C[i].begin(),di=D[i].begin();ci!=C[i].end();ci++,di++)	updata(1,n,1,1,*ci,*di);
    		f[i]=s[1],p.push(A[i]+f[i]);
    	}
    	printf("%I64d
    ",p.top());
    	for(i=1;i<=q;i++)
    	{
    		a=rd(),p.erase(A[a]+f[a]),A[a]=rd(),p.push(A[a]+f[a]);
    		printf("%I64d
    ",p.top());
    	}
    	return 0;
    }
  • 相关阅读:
    POJ2528——Mayor's posters (线段树区间更新查询+离散化)
    C++STL——unique函数总结
    HDU 5618 Jam's problem again(CDQ分治+树状数组(三维模板题))
    c++解决爆栈,手动加栈!
    POJ1741——Tree (树分治之点分治)
    树分治之点分治模板总结
    CodeForces
    字典树
    卡特兰数高精度算法
    基数排序
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8097392.html
Copyright © 2020-2023  润新知