「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\n",ans);
	return 0;
}
												
											「SNOI2019」通信的更多相关文章
- 【LOJ】#3097. 「SNOI2019」通信
		
LOJ#3097. 「SNOI2019」通信 费用流,有点玄妙 显然按照最小路径覆盖那题的建图思路,把一个点拆成两种点,一种是从这个点出去,标成\(x_{i}\),一种是输入到这个点,使得两条路径合成 ...
 - 「SNOI2019」通信 分治优化费用流建图
		
题意: n 个排成一列的哨站要进行通信.第 i 个哨站的频段为 ai. 每个哨站 ii 需要选择以下二者之一: 1.直接连接到控制中心,代价为 W:2.连接到前面的某个哨站 j(j<i),代价为 ...
 - 「SNOI2019」通信 分治建图
		
根据题意 每个点可以直接与S,T相连 也可以和前面的哨站相连 暴力建边的话 有n2条边 要用分治优化建边: 类似于归并排序 先对每一层分为左半边与右半边 对每一半都拿出来先排序去重后 直接排成一条链建 ...
 - Loj #3096. 「SNOI2019」数论
		
Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...
 - 【LOJ】#3098. 「SNOI2019」纸牌
		
LOJ#3098. 「SNOI2019」纸牌 显然选三个以上的连续牌可以把他们拆分成三个三张相等的 于是可以压\((j,k)\)为有\(j\)个连续两个的,有\(k\)个连续一个的 如果当前有\(i\ ...
 - 【LOJ】#3096. 「SNOI2019」数论
		
LOJ#3096. 「SNOI2019」数论 如果\(P > Q\)我们把\(P\)和\(Q\)换一下,现在默认\(P < Q\) 这个时候每个合法的\(a_i\)都可以直接落到\(Q\) ...
 - 【LOJ】#3095. 「SNOI2019」字符串
		
LOJ#3095. 「SNOI2019」字符串 如果两个串\(i,j\)比较\(i < j\),如果离\(a_{i}\)最近的不同的数是\(a_{k}\),如果\(j < k\)那么\(i ...
 - 「SNOI2019」字符串
		
题目 看起来非常一眼啊,我们完全可以\(std::sort\)来解决这歌问题 于是现在的问题转化成了比较函数怎么写 随便画一下就会发现前面的好几位是一样的,后面的好几位也是一样,只需要比较中间的一段子 ...
 - 「SNOI2019」积木
		
传送门 Description 有一块\(n\)行\(m\)列的网格板, \(n,m\)都是奇数.网格上平铺着一些\(1*2\)的积木.积木可以旋转,不能重叠.网格板上只有一格的空位. 你可以做两种操 ...
 
随机推荐
- [Luogu 3787] 冰精冻西瓜
			
Description 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃. 这些西瓜蔓具有神奇的性质, ...
 - MyBatis从入门到放弃三:一对一关联查询
			
前言 简单来说在mybatis.xml中实现关联查询实在是有些麻烦,正是因为起框架本质是实现orm的半自动化. 那么mybatis实现一对一的关联查询则是使用association属性和resultM ...
 - SQL 数据库加字段声明
			
ALTER TABLE dbo.C_TrainPlan ADD MailCost DATETIME EXECUTE sp_addextendedproperty N'MS_Description', ...
 - java.. C# 使用AES加密互解 采用AES-128-ECB加密模式
			
java需要下载外部包, commons codec.jar 1.6 較新的JAVA版本把Base64的方法改成靜態方法,可能會寫成Base64.encodeToString(encrypted, ...
 - 非常完善的Log4net详细说明(转)
			
最可能来源:https://blog.csdn.net/ydm19891101/article/details/50561638 其它转载者:http://www.cnblogs.com/zhangc ...
 - Java开发中json使用,各对象与json相互转换
			
Json:一种网络通信使用的数据格式,因为便于解析,比较流行,对象可以转为json,同样json也可以转对象. 下面介绍下Json工具的简单使用(fastjson && jackson ...
 - Spring基于注解和XML混合方式的使用
			
首先要明白,基于注解和XML两种方式的实现功能是一样的,只是两种不同的配置方式. 一.IoC配置 1.配置xml 在使用注解与xml结合的方式配置IoC之前,首先要引入context标签: xmlns ...
 - css兼容问题(一)
			
开头语:不用就忘,还是自己乖乖的记笔记吧! 正文开始: (一)如果你的页面对IE7兼容没有问题,又不想大量修改现有代码,同时又能在IE8中正常使用,微软声称,开发商仅需要在目前兼容IE7的网站上 ...
 - array.js
			
// “最后加” concat 连接两个或更多的数组,并返回结果. var a = ['a','b','c']; var b = ['x','y','z']; var c = a.concat(b,t ...
 - 【代码笔记】Web-HTML-图像
			
一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...