zoukankan      html  css  js  c++  java
  • CF903G Yet Another Maxflow Problem

    题目链接:戳我

    最小割+线段树模拟网络流


    (自己手动画了一个图,有点丑还请见谅)
    首先声明一些数组:a[i]表示左边图编号为i的线段的长度,b[i]表示右边图编号为i的线段的长度,sum[i]表示选取左边编号为i的线段的最小代价。

    下面我们来看这个题怎么做——

    比较神仙。既然题目中都说了"yet another maxflow problem",那肯定不是用最大流来写的。我们考虑转化,转化成最小割。(你问我为什么?我我我。。。我也不太清楚,就当做一个套路吧,而且网络流二分图中的最大流不也很有一部分题目是转化成最小割来写的嘛qwqwq)

    转化了之后我们就知道答案肯定是(dis_{(A_i,A_i+1)}+dis_{(B_i,B_i+1)}+sum dis_{(p,q)},ple i,qge j)

    我们可以考虑从小到大遍历一遍A,(设现在遍历到的点为u)然后枚举它的出边所指向的v。对于(u,v)这条边,显然它的贡献只产生于(ile u,jge v)的边里面。又因为左边遍历的时候已经保证顺序了,所以我们只需要在维护(b)值的区间里加上它的值作为贡献即可。

    然后我们重新构建一次线段树。。。查询全局最小值。每次修改就是简单的单点修改。

    然后。。就没有然后了。。。。就做完了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define MAXN 200010
    using namespace std;
    int n,m,q,edge_number;
    int head[MAXN];
    long long a[MAXN],b[MAXN],sum[MAXN];
    struct Node{int l,r;long long minn,tag;}t[MAXN<<2];
    struct Edge{int nxt,to;long long dis;}edge[MAXN<<1];
    inline void add(int from,int to,long long dis)
    {
    	edge[++edge_number].nxt=head[from];
    	edge[edge_number].to=to;
    	edge[edge_number].dis=dis;
    	head[from]=edge_number;
    }
    inline int ls(int x){return x<<1;}
    inline int rs(int x){return x<<1|1;}
    inline void push_up(int x){t[x].minn=min(t[ls(x)].minn,t[rs(x)].minn);}
    inline void solve(int x,long long k)
    {
    	t[x].tag+=k;
    	t[x].minn+=k;
    }
    inline void push_down(int x)
    {
    	if(t[x].tag)
    	{
    		solve(ls(x),t[x].tag);
    		solve(rs(x),t[x].tag);
    		t[x].tag=0;
    	}
    }
    inline void build(int x,int l,int r,int op)
    {
    	t[x].l=l,t[x].r=r;
    	if(l==r) 
    	{
    		if(op==0) t[x].minn=b[l];
    		else t[x].minn=sum[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(ls(x),l,mid,op);
    	build(rs(x),mid+1,r,op);
    	push_up(x);
    }
    inline void build2(int x,int l,int r)
    {
    	t[x].l=l,t[x].r=r;
    	if(l==r) {t[x].minn=sum[l];return;}
    	int mid=(l+r)>>1;
    	build2(ls(x),l,mid);
    	build2(rs(x),mid+1,r);
    	push_up(x);
    }
    inline void update(int x,int ll,int rr,long long k)
    {
    	int l=t[x].l,r=t[x].r;
    	if(ll<=l&&r<=rr) {solve(x,k);return;}
    	int mid=(l+r)>>1;
    	push_down(x);
    	if(ll<=mid) update(ls(x),ll,rr,k);
    	if(mid<rr) update(rs(x),ll,rr,k);
    	push_up(x);
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d%d%d",&n,&m,&q);
    	for(int i=1;i<n;i++) scanf("%I64d%I64d",&a[i],&b[i]);
    	for(int i=1;i<=m;i++)
    	{
    		int u,v;
    		long long w;
    		scanf("%d%d%I64d",&u,&v,&w);
    		add(u,v,w);
    	}
    	build(1,0,n-1,0);
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=head[i];j;j=edge[j].nxt)
    		{
    			int v=edge[j].to;
    			update(1,0,v-1,edge[j].dis);
    		}
    		sum[i]=a[i]+t[1].minn;
    	}
    	//for(int i=1;i<=n;i++) printf("sum[%d]=%I64d
    ",i,sum[i]);
    	memset(t,0,sizeof(t));
    	build(1,1,n,1);
    	printf("%I64d
    ",t[1].minn);
    	for(int i=1;i<=q;i++)
    	{
    		int u;
    		long long k;
    		scanf("%d%I64d",&u,&k);
    		update(1,u,u,k-a[u]);
    		a[u]=k;
    		printf("%I64d
    ",t[1].minn);
    	}
    	return 0;
    }
    
  • 相关阅读:
    PHP实现无限极分类
    html2canvas生成并下载图片
    一次线上问题引发的过程回顾和思考,以更换两台服务器结束
    Intellij IDEA启动项目报Command line is too long. Shorten command line for XXXApplication or also for
    mq 消费消息 与发送消息传参问题
    idea 创建不了 java 文件
    Java switch 中如何使用枚举?
    Collections排序
    在idea 设置 git 的用户名
    mongodb添加字段和创建自增主键
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10510165.html
Copyright © 2011-2022 走看看