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

    「SNOI2019」通信

    传送门

    Loj

    题解

    首先考虑一个最暴力的(O(n^2))连边的费用流,即拆点然后(s ightarrow i,i+n ightarrow t,s ightarrow i+n).

    中间的连边考虑(i ightarrow j+n)表示(j)连到了(i)这个点.

    左右的边数都是(O(n))级别的,考虑中间连边的优化.

    可以想想(cdq)分治,考虑左边的点对右边的连边,这个东西可以用前后缀优化连边,然后建一排虚点即可.

    代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    #include<set>
    #include<map>
    using namespace std;
    #define mp make_pair
    #define ll long long
    #define re register
    typedef pair<int,int> pii;
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    inline int gi()
    {
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=200010,M=2000010,Inf=1e9+10;
    int front[N],cnt,n,m,vis[N],s,t,fa[N],from[N],W,a[N],p[N],tot,p1[N];
    struct node{int to,nxt,w,f;}e[M<<1];
    ll ans,dis[N];
    queue<int>Q;
    void Add(int u,int v,int w,int f)
    {
    	e[cnt]=(node){v,front[u],w,f};front[u]=cnt++;
    	e[cnt]=(node){u,front[v],0,-f};front[v]=cnt++;
    }
    bool SPFA()
    {
    	memset(dis,63,sizeof(dis));memset(vis,0,sizeof(vis));
    	Q.push(s);dis[s]=0;vis[s]=1;
    	while(!Q.empty())
    	{
    		int u=Q.front();Q.pop();vis[u]=0;
    		for(int i=front[u];~i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(e[i].w&&dis[v]>dis[u]+e[i].f)
    			{
    				dis[v]=dis[u]+e[i].f;fa[v]=u;from[v]=i;
    				if(!vis[v]){Q.push(v);vis[v]=1;}
    			}
    		}
    	}
    	if(dis[t]>1e9+10)return false;
    	int di=Inf;
    	for(int i=t;i!=s;i=fa[i])di=min(di,e[from[i]].w);
    	ans+=1ll*di*dis[t];
    	for(int i=t;i!=s;i=fa[i])e[from[i]].w-=di,e[from[i]^1].w+=di;
    	return true;
    }
    void solve(int l,int r)
    {
    	if(l==r)return;
    	int mid=(l+r)>>1,sz=0;
    	solve(l,mid);solve(mid+1,r);
    	for(int i=l,j=mid+1;i<=mid||j<=r;)
    		p1[++sz]=p[j>r||(i<=mid&&a[p[i]]<a[p[j]])?i++:j++];
    	for(int i=1;i<sz;i++)
    	{
    		Add(tot+i,tot+i+1,Inf,a[p1[i+1]]-a[p1[i]]);
    		Add(tot+i+1,tot+i,Inf,a[p1[i+1]]-a[p1[i]]);
    	}
    	for(int i=1;i<=sz;i++)
    		if(p1[i]<=mid)Add(p1[i],tot+i,1,0);
    		else Add(tot+i,p1[i]+n,1,0);
    	tot+=sz;
    	for(int i=l;i<=r;i++)p[i]=p1[i-l+1];
    }
    int main()
    {
    	memset(front,-1,sizeof(front));
    	n=gi();W=gi();s=0;tot=t=n<<1|1;
    	for(int i=1;i<=n;i++)a[i]=gi(),p[i]=i;
    	for(int i=1;i<=n;i++)Add(s,i,1,0),Add(i+n,t,1,0),Add(s,i+n,1,W);
    	solve(1,n);
    	while(SPFA());
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    软件工程(2019)第二次作业
    软件工程(2019)第一次作业
    Java基础篇之Java特性
    软件工程(2019)结对编程第二次作业
    软件工程(2019)结对编程第一次作业
    软件工程(2019)第三次作业
    软件工程(2019)第二次作业
    软件工程(2019)第一次作业
    结对编程作业 2
    结对编程作业 1
  • 原文地址:https://www.cnblogs.com/fexuile/p/13026333.html
Copyright © 2011-2022 走看看