zoukankan      html  css  js  c++  java
  • 「SNOI2019」通信

    题目

    还好我没生在陕西啊

    首先发现这个题不能(dp),数据范围不大,好像一种网络流的样子啊

    哎等等,这样向后面连边不是一个(DAG)吗,这不是最小权路径覆盖的板子吗

    于是我们套路的拆点,对于一个点(i)我们拆成(i)(i'),源点向点(i)连费用为(0)容量为(1)的边,(i')向汇点连费用为(0)容量为(1)的边

    之后我们把让(S)(i')直接连费用为(W)容量为(1)的边,表示直接连到控制中心

    对于点(i),我们向(j'(j>i))连容量为(1)费用为(|a_i-a_j|)的边,表示点(j)接到了点(i)后面

    于是现在我们一个最小费用最大流就好了

    之后喜提(TLE)

    我们发现我们好像建出了(n^2)级别的边

    我们考虑我们连边的方式,这样向后面一个区间连边的方式让人好熟悉啊,这不是线段树优化建图吗

    但是我们注意到这里的边的费用好像不是一样的,但是这个绝对值给了我们分类讨论的可能

    对于一个点(i),我们建出一个虚点(x')(i)(x')连费用为(a_i)的边,让这个虚点(x')(j(j>i,a_j<a_i))连费用为(-a_j)的边,(a_j>a_i)同理,这样我们就能实现绝对值这个问题了

    那么我们如何快速向一个点之后的所有大于它或小于它的点连边呢

    直接主席树优化建图就好了,这样我们的点数和边数都是(nlogn)级别的了

    但是还是(T),发现我们建了两万多个点和十万多条边

    写一个快一点的费用流就好了,用zkw费用流和(slf)优化的spfa勉勉强强能跑过的样子

    另外(loj)上的大爷们写的看起来好像(cdq)分治优化建图的洞西看起来好神仙啊

    代码

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #pragma GCC optimize(3)
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const LL inf=999999999999;
    const int fnf=999999999;
    const int maxn=2e3+5;
    const int M=4e5+6;
    int head[M],vis[M],a[maxn],c[maxn],b[maxn];LL d[M];
    int rt[maxn][2],l[M],r[M];
    struct E{int v,nxt,w,f;}e[200005];
    int n,num=1,S,T,W,sz,cnt;
    inline void C(int x,int y,int w,int f) {
    	e[++num].v=y;e[num].nxt=head[x];
    	e[num].w=w;e[num].f=f;head[x]=num;
    }
    std::deque<int> q;
    inline void add(int x,int y,int w,int f) {C(x,y,w,f),C(y,x,-1*w,0);}
    inline int SPFA() {
    	for(re int i=S;i<=cnt;i++) d[i]=inf,vis[i]=0;
    	d[T]=0,q.push_back(T);
    	while(!q.empty()) {
    		int k=q.front();q.pop_front();vis[k]=0;
    		for(re int i=head[k];i;i=e[i].nxt)
    		if(e[i^1].f&&d[e[i].v]>d[k]+e[i^1].w) {
    			d[e[i].v]=d[k]+e[i^1].w;
    			if(!vis[e[i].v]) {
    				vis[e[i].v]=1;
    				if(q.empty()) {q.push_back(e[i].v);continue;}
    				if(d[e[i].v]<d[q.front()]) q.push_front(e[i].v);
    					else q.push_back(e[i].v);
    			}
    		}
    	}
    	return d[S]<inf;
    }
    int dfs(int x,int now) {
    	if(x==T||!now) return now;
    	int flow=0,ff;vis[x]=1;
    	for(re int i=head[x];i;i=e[i].nxt)
    	if(e[i].f&&!vis[e[i].v]&&d[e[i].v]==d[x]+e[i^1].w) {
    		ff=dfs(e[i].v,min(e[i].f,now));
    		if(ff<=0) continue;
    		flow+=ff,now-=ff,e[i].f-=ff,e[i^1].f+=ff;
    		if(!now) break;
    	}
    	return flow;
    }
    inline int find(int x) {
    	int lx=1,ry=sz;
    	while(lx<=ry) {
    		int mid=lx+ry>>1;
    		if(c[mid]==x) return mid;
    		if(c[mid]<x) lx=mid+1;
    			else ry=mid-1;
    	}
    	return 0;
    }
    int ins(int pre,int x,int y,int pos,int a,int b) {
    	int root=++cnt;
    	if(x==y) {
    		add(root,a,b*c[x],1);
    		return root;
    	}
    	int mid=x+y>>1;
    	l[root]=l[pre],r[root]=r[pre];
    	if(pos<=mid) l[root]=ins(l[pre],x,mid,pos,a,b);
    		else r[root]=ins(r[pre],mid+1,y,pos,a,b);
    	if(l[root]) add(root,l[root],0,fnf);
    	if(r[root]) add(root,r[root],0,fnf);
    	return root;
    }
    void Con(int g,int now,int x,int y,int lx,int ry) {
    	if(!now) return;
    	if(lx<=x&&ry>=y) {add(g,now,0,fnf);return;} 
    	int mid=x+y>>1;
    	if(lx<=mid) Con(g,l[now],x,mid,lx,ry);
    	if(ry>mid) Con(g,r[now],mid+1,y,lx,ry);
    }
    int main() {
    	n=read(),W=read();S=0,T=n+n+1;cnt=T;
    	for(re int i=1;i<=n;i++) a[i]=read();
    	for(re int i=1;i<=n;i++) add(S,i+n,W,1);
    	for(re int i=1;i<=n;i++) add(S,i,0,1);
    	for(re int i=1;i<=n;i++) add(i+n,T,0,1);
    	for(re int i=1;i<=n;i++) c[i]=a[i];
    	std::sort(c+1,c+n+1);sz=std::unique(c+1,c+n+1)-c-1;
    	for(re int i=1;i<=n;i++) b[i]=a[i],a[i]=find(a[i]);
    	for(re int i=n;i>1;--i) 
    		rt[i][0]=ins(rt[i+1][0],1,sz,a[i],i+n,-1),
    		rt[i][1]=ins(rt[i+1][1],1,sz,a[i],i+n,1);
    	for(re int i=1;i<n;i++) {
    		++cnt;
    		add(i,cnt,b[i],1);
    		Con(cnt,rt[i+1][0],1,sz,1,a[i]);
    		++cnt;
    		add(i,cnt,-1*b[i],1);
    		Con(cnt,rt[i+1][1],1,sz,a[i],sz);
    	} 
    	LL ans=0;
    	while(SPFA()) {
    		vis[T]=1;
    		while(vis[T]) {
    			for(re int i=S;i<=cnt;i++) vis[i]=0;
    			ans+=1ll*dfs(S,fnf)*d[S];
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    和类的初识
    IIFE
    闭包的二次理解
    5分钟搞懂ECE雾计算
    机智云推出设备联动API,打造智能家居场景化
    神奇的【设备联动API】,助力智能家居/家电场景化
    STM32峰会2017:半小时开发基于STM32的室内智能环境监测仪
    STM32峰会:机智云MCU代码开发工具降低智能硬件开发成本
    广和通G510联网固件首发,支持连接机智云
    各种STM32连接机智云案例汇总(不定期更新,欢迎补充)
  • 原文地址:https://www.cnblogs.com/asuldb/p/10786155.html
Copyright © 2011-2022 走看看