zoukankan      html  css  js  c++  java
  • 【纪中集训2019.3.21】桥

    题意

    描述

    (M)条河,每条河的两边有居民点,所以共有(M+1)排居名点;

    如果要从一排居名点到另一排相邻的居民点需要过河;

    现在有(n)个人,每个人的起点坐标是((P_{i},S_{i})),终点((Q_{i},T_{i}))

    你可以在每条河上修建一座桥,过河必须通过桥;

    相邻居民点距离为(1),不考虑过河的时间;

    (n)个人到终点的路径之和最小是多少;

    范围

    (1 le N , M le 10^5 , 1 le S_{i} ,T_{i} le 10^9 , 1 le P_{i},Q_{i} le M+1)

    题解:

    • 答案一定在(S_{i})或者(T_{i})上(我不会证明。。。)

    • 考虑所有的可行位置为(a_{i})

    • 一条路径的贡献可以放到每座桥上,分为两部分:

      • 经过桥(i 和 i - 1) (b_{i})次;
      • (a_{k})到桥(i)(a_{k})为某个起点或者终点,设(g_i(j) = sum_{k}|a_{k}-a_{j}|)

      [egin{align} f_{1,j} &= g_{1}(j) &(i=1) \ f_{i,j} &= min { f_{i-1,k} + b_{i} |a_{i}-a_{k}| + g_{i}(j) } &(i gt 1) \ end{align} ]

    • 所以得到一个(O(n^2m))(dp),可以用单调队列简单优化到(O(nm))

    • (g_{1})一定是凸函数,所以(f_{1})一定是凸的,同时由于凸函数对加法封闭,所以直接考虑转移前半部分:

    • 考虑在(f_{i-1})上找到两个斜率为 (-b_{i})(b_{i})的点设为(j1和j2)

    • [f_{i,j} = g_{i}(j) + egin{cases} &f_{i-1,j1} &+& b_{i} |a_{i}-a_{j1}| &(j lt j1)\ &f_{i-1,j} &+ &b_{i} |a_{i}-a_{j}| &(j1 le j le j2)\ &f_{i-1,j2} &+ &b_{i} |a_{i}-a_{j2}| &(j2 lt j)\ end{cases} ]

    • (分析绝对值简单比较就可以得到)

    • 所以(f_{i-1} o f_{i})就是区间赋值一次函数,区间加一次函数,所以(f_{i})仍然是凸的;

    • 用线段树或者(set)维护差分即可;

    • 注意要另外维护一下(f_{i,1}) ;

      #include<bits/stdc++.h>
      #define pb push_back
      #define mk make_pair
      #define ls (k<<1)
      #define rs (k<<1|1)
      #define ll long long 
      #define inf 1e18
      #define il inline 
      using namespace std;
      const int N=100010;
      int n,m,tot,sub[N<<1],P[N],S[N],Q[N],T[N];
      vector<int>a[N];
      ll B,sum[N],b[N],ans;
      il char gc(){
      	static char*p1,*p2,s[1000000];
      	if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
      	return(p1==p2)?EOF:*p1++;
      }
      il int rd(){
      	int x=0;char c=gc();
      	while(c<'0'||c>'9')c=gc();
      	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
      	return x;
      }
      ll s[N<<3],d[N<<3],dr[N<<3],ly1[N<<3],ly2[N<<3];
      il void build(int k,int l,int r){
      	ly2[k]=inf;
      	if(l==r){
      		if(!l)d[l]=-inf;
      		if(l==tot)d[l]=inf;
      		return;
      	}
      	int mid=l+r>>1;
      	build(ls,l,mid);
      	build(rs,mid+1,r);
      }
      il void mfy1(int k,int l,int r,ll x){
      	d[k]+=x;dr[k]+=x;ly1[k]+=x;
      	s[k]+=(sub[r+1]-sub[l])*x;
      }
      il void mfy2(int k,int l,int r,ll x){
      	d[k]=dr[k]=ly2[k]=x;ly1[k]=0;
      	s[k]=(sub[r+1]-sub[l])*x; 
      }
      il void pushup(int k,int l,int r){
      	s[k]=s[ls]+s[rs];
      	dr[k]=dr[rs];
      }
      il void pushdown(int k,int l,int r){
      	if(ly2[k]!=inf){
      		int mid=l+r>>1; 
      		mfy2(ls,l,mid,ly2[k]);
      		mfy2(rs,mid+1,r,ly2[k]);
      		ly2[k]=inf;
      	}
      	if(ly1[k]){
      		int mid=l+r>>1;
      		mfy1(ls,l,mid,ly1[k]);
      		mfy1(rs,mid+1,r,ly1[k]);
      		ly1[k]=0;
      	}
      }
      void update1(int k,int l,int r,int x,int y,ll v){
      	if(l==x&&r==y){mfy1(k,l,r,v);return;}
      	int mid=(l+r)>>1;
      	pushdown(k,l,r);
      	if(y<=mid)update1(ls,l,mid,x,y,v);
      	else if(x>mid)update1(rs,mid+1,r,x,y,v);
      	else update1(ls,l,mid,x,mid,v),update1(rs,mid+1,r,mid+1,y,v);
      	pushup(k,l,r);
      }
      void update2(int k,int l,int r,int x,int y,ll v){
      	if(l==x&&r==y){mfy2(k,l,r,v);return;}
      	int mid=(l+r)>>1;
      	pushdown(k,l,r);
      	if(y<=mid)update2(ls,l,mid,x,y,v);
      	else if(x>mid)update2(rs,mid+1,r,x,y,v);
      	else update2(ls,l,mid,x,mid,v),update2(rs,mid+1,r,mid+1,y,v);
      	pushup(k,l,r);
      }
      int query1(int k,int l,int r,ll x){
      	if(l==r)return l;
      	int mid=l+r>>1;
      	pushdown(k,l,r);
      	if(dr[ls]>=x)return query1(ls,l,mid,x);
      	else return query1(rs,mid+1,r,x);
      }
      ll query2(int k,int l,int r,int x,int y){
      	if(l==x&&r==y)return s[k];
      	pushdown(k,l,r);
      	int mid=l+r>>1;
      	if(y<=mid)return query2(ls,l,mid,x,y);
      	else if(x>mid)return query2(rs,mid+1,r,x,y);
      	else return query2(ls,l,mid,x,mid)+query2(rs,mid+1,r,mid+1,y);
      }
      il void Update1(int cur){
      	sort(a[cur].begin(),a[cur].end());
      	int sz=a[cur].size();
      	a[cur].push_back(tot);
      	ans+=sum[cur];
      	for(int i=0,now=1,lst=1;i<=sz;++i){
      		lst=now,now=a[cur][i];
      		int x=2*i-sz;
      		if(lst<now)update1(1,0,tot,lst,now-1,x);
      	}
      }
      il void Update2(int cur){
      	int x1=query1(1,0,tot,-b[cur]);
      	int x2=query1(1,0,tot,b[cur]);
      	if(1<x1){
      		ans=ans+query2(1,0,tot,1,x1-1)+1ll*(sub[x1]-sub[1])*b[cur];
      		update2(1,0,tot,1,x1-1,-b[cur]);
      	}
      	if(x2<tot){update2(1,0,tot,x2,tot-1,b[cur]);}
      }
      int main(){
      	freopen("bridge.in","r",stdin);
      	freopen("bridge.out","w",stdout);
      	n=rd();m=rd();
      	for(int i=1;i<=n;++i){
      		P[i]=rd()-1;S[i]=rd();Q[i]=rd()-1;T[i]=rd();
      		if(P[i]>Q[i])swap(P[i],Q[i]),swap(S[i],T[i]);
      		sub[++tot]=S[i],sub[++tot]=T[i];
      	}
      	sub[++tot]=1;
      	sort(sub+1,sub+tot+1);
      	tot=unique(sub+1,sub+tot+1)-sub-1;
      	for(int i=1;i<=n;++i){
      		S[i]=lower_bound(sub+1,sub+tot+1,S[i])-sub;
      		T[i]=lower_bound(sub+1,sub+tot+1,T[i])-sub; 
      		int l=P[i],r=Q[i];
      		if(l==r){ans+=abs(sub[T[i]]-sub[S[i]]);continue;}
      		a[l+1].pb(S[i]);sum[l+1]+=sub[S[i]]-1;
      		a[r].pb(T[i]);sum[r]+=sub[T[i]]-1;
      		b[l+2]++,b[r+1]--;
      	}
      	build(1,0,tot);
      	Update1(1);
      	for(int i=2;i<=m;++i){
      		b[i]+=b[i-1];
      		Update2(i);
      		Update1(i);
      	}
      	int pos=query1(1,0,tot,0);
      	if(pos>1)ans+=query2(1,0,tot,1,pos-1);
      	printf("%lld
      ",ans);
      	return 0;
      }
      
      //这是fxy写的set;
      #pragma GCC optimize(3)
      #include<iostream>
      #include<cstdio>
      #include<queue>
      #include<cstring>
      #include<cmath>
      #include<stack>
      #include<set>
      #include<algorithm>
      #define rg register
      #define ll long long
      #define LDB long double
      #define ull unsigned long long
      #define view(i,x) for(rg int i=hd[x];i!=-1;i=e[i].nt)
      #define go(i,x,a) for(rg int i=a;i<x;i++)
      #define inf 0x3f3f3f3f
      #define INF 0x7fffffff
      using namespace std;
      
      const int maxn=1e5+5;
      int n,m,f[maxn],l,r;
      vector<int>g[maxn];
      multiset<int>s,t;
      ll ans=0;
      
      inline int rd(){
          int ret=0,af=1; char gc=getchar();
          while(gc < '0' || gc > '9'){ if(gc=='-') af=-af; gc=getchar(); }
          while(gc >= '0' && gc <= '9') ret=ret*10+gc-'0',gc=getchar();
          return ret*af;
      }
      
      inline void update(int x){
      	if(l <= x && x <= r){
      		s.insert(x); t.insert(x);
      		l=r=x; return ;
      	}
      	if(x < l){
      		ans+=l-x; s.erase(s.find(l));
      		if(s.find(l) == s.end()){
      			r=l; l=s.size() > 1 ? *(--s.end()):x;
      		}else r=l;
      		s.insert(x); s.insert(x); t.insert(r);
      		return ;
      	}
      	if(x > r){
      		ans+=x-r; t.erase(t.find(r));
      		if(t.find(r) == t.end()){
      			l=r; r=t.size() > 1 ? *(t.begin()):x;
      		}else l=r;
      		t.insert(x); t.insert(x); s.insert(l);
      	}
      }
      
      int main(){
          //#ifndef ONLINE_JUDGE
          freopen("bridge.in","r",stdin);
          freopen("bridge.out","w",stdout);
          //#endif
          n=rd(); m=rd(); int p,q,a,b;
          go(i,n+1,1){
          	p=rd(); a=rd(); q=rd(); b=rd();
          	if(p == q){ ans+=abs(a-b); continue; }
          	if(p > q) swap(p,q),swap(a,b);
          	g[p].push_back(a);
          	g[q-1].push_back(b);
          	if(p+1 <= q-1) f[p+1]++,f[q]--;
      	}
      	go(i,m+1,1) f[i]+=f[i-1];
      	l=0; r=inf;
      	s.insert(l); t.insert(r);
      	go(i,m+1,1){
      		if(i > 1){
      			while(s.size() > f[i]) s.erase(s.begin());
      			while(t.size() > f[i]) t.erase(--t.end());
      			if(s.size() == 0) s.insert(0);
      			if(t.size() == 0) t.insert(inf);
      		}
      		go(j,g[i].size(),0) update(g[i][j]);
      	}
      	printf("%lld",ans);
          return 0;
      }
      
  • 相关阅读:
    关于VS2005使用VC++创建MFC智能设备应用程序,总是创建失败解决方法
    远峰E路航V700pro进入wince桌面方法与安装游戏方法
    Arduino IDE上搭建ESP8266环境
    JavaScript Tutorial
    TinyOS Term & Example
    Installation for TinyOS on Ubuntu 16.04
    MySQL Manipulation
    泰勒级数&傅立叶级数(通信层面)
    Choose a different branch in github
    初窥Makefile
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10574398.html
Copyright © 2011-2022 走看看