其他分享
首页 > 其他分享> > P5331 [SNOI2019]通信

P5331 [SNOI2019]通信

作者:互联网

说在前面的话

今天异常颓废突发奇想,想要把自己之前这道题目的奇怪做法记录一下,可是发现洛谷已经有人捷足先登了

题解

你发现对于每一个站点,它需要和前面的每一个站点连边,同时对于比他大的和比他小的权值计算方式不一样,我们就考虑用主席树优化建图,然后就好了。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e3+5;
const int INF=1e9+7;
int n,w;
struct Data{int data,pos;}a[N];int L[N],R[N];
bool cmp(const Data a,const Data b){return a.data<b.data;}
int from,to,id[2][N],tot=0;
struct Edge{int nxt,to,flow,cost;};vector<Edge> e;int fir[N<<6];
void add(int u,int v,int x,int y){e.push_back((Edge){fir[u],v,x,y}),fir[u]=e.size()-1;}
struct Per_Seg_Tree{
	int rt[2][N];
	struct Node{int id,ls,rs;}tr[N<<6];
	void insert(int u,int v,int l,int r,int x,int cost){
		tr[v]=tr[u];
		if(l==r) return add(v,id[1][l],1,cost),add(id[1][l],v,0,-cost);
		int mid=(l+r)>>1;
		if(x<=mid) tr[v].ls=++tot,insert(tr[u].ls,tr[v].ls,l,mid,x,cost);
		else tr[v].rs=++tot,insert(tr[u].rs,tr[v].rs,mid+1,r,x,cost);
		add(v,tr[v].ls,INF,0),add(tr[v].ls,v,0,0);
		add(v,tr[v].rs,INF,0),add(tr[v].rs,v,0,0);
	}
	void add_edge(int u,int l,int r,int x,int y,int id,int cost){
		if(!u||x>y) return ;
		if(x<=l&&r<=y) return add(id,u,1,cost),add(u,id,0,-cost);
		int mid=(l+r)>>1;
		if(x<=mid) add_edge(tr[u].ls,l,mid,x,y,id,cost);
		if(y>mid) add_edge(tr[u].rs,mid+1,r,x,y,id,cost);
	}
}t;
queue<int> q;bool vis[N<<6];
int dis[N<<6],cur[N<<6],res=0;
bool bfs(){
	for(int i=1;i<=tot;++i) dis[i]=INF,cur[i]=fir[i];
	dis[from]=0,vis[from]=true,q.push(from);
	while(!q.empty()){
		int u=q.front();vis[u]=false,q.pop();
		for(int i=fir[u];i>=0;i=e[i].nxt){
			int v=e[i].to;
			if(!e[i].flow||dis[v]<=dis[u]+e[i].cost) continue;
			dis[v]=dis[u]+e[i].cost;
			if(!vis[v]) vis[v]=true,q.push(v);
		}
	}
	return dis[to]!=INF;
}
int dfs(int u,int flow){
	if(u==to) return flow;
	int res=0;vis[u]=true;
	for(int i=cur[u];i>=0&&flow;i=e[i].nxt){
		int v=e[i].to;cur[u]=i;
		if(!e[i].flow||dis[v]!=dis[u]+e[i].cost||vis[v]) continue;
		int tmp=dfs(v,min(e[i].flow,flow));
		e[i].flow-=tmp,e[i^1].flow+=tmp,flow-=tmp,res+=tmp;
	}
	return vis[u]=false,res;
}
signed main(){
	cin>>n>>w;
	for(int i=1;i<=n;++i){
		scanf("%lld",&a[i].data),a[i].pos=i;
	}
	sort(a+1,a+1+n,cmp);
	from=++tot,to=++tot;
	memset(fir,-1,sizeof(fir));
	for(int i=1;i<=n;++i){
		id[0][i]=++tot,id[1][i]=++tot;
		add(from,id[0][i],1,0),add(id[0][i],from,0,0);
		add(id[1][i],to,1,0),add(to,id[1][i],0,0);
	}
	a[0].data=a[n+1].data=INF;
	for(int i=1;i<=n;++i){
		t.rt[0][i]=++tot,L[i]=(a[i].data==a[i-1].data)?L[i-1]:i;
		t.insert(t.rt[0][i-1],t.rt[0][i],1,n,a[i].pos,-a[i].data);
	}
	for(int i=n;i>=1;--i){
		t.rt[1][i]=++tot,R[i]=(a[i].data==a[i+1].data)?R[i+1]:i;
		t.insert(t.rt[1][i+1],t.rt[1][i],1,n,a[i].pos,a[i].data);
	}
	for(int i=1;i<=n;++i){
		add(id[0][i],to,1,w),add(to,id[0][i],0,-w);
		// printf("---%lld %lld %lld\n",a[i].pos,L[i],R[i]);
		t.add_edge(t.rt[0][R[i]],1,n,1,a[i].pos-1,id[0][a[i].pos],a[i].data);
		t.add_edge(t.rt[1][L[i]],1,n,1,a[i].pos-1,id[0][a[i].pos],-a[i].data);
	}
	while(bfs()) res+=dis[to]*dfs(from,INF);
	printf("%lld\n",res);
	return 0;
}

标签:tmp,P5331,const,int,flow,通信,return,SNOI2019,data
来源: https://www.cnblogs.com/Point-King/p/14427133.html