http://www.51nod.com/Challenge/Problem.html#!#problemId=1781
题解
核心问题:漏斗从1到n都必须覆盖到,用到dp思想:分别从左往右和从右往左算出小球移动到当前漏斗的最少花费,最后再减去重复的最后一支漏斗的花费更新答案。
具体:把列离散化,然后对列建线段树维护区间最小值,区间查询移动到当前漏斗的最少花费,查询后对漏斗的出口进行单点更新。
1 #define dbg(x) cout<<#x<<" = "<< (x)<< endl 2 #define IO std::ios::sync_with_stdio(0); 3 #include4 #define iter ::iterator 5 using namespace std; 6 typedef long long ll; 7 typedef pair P; 8 #define pb push_back 9 #define se second 10 #define fi first 11 #define rs o<<1|1 12 #define ls o<<1 13 const ll inf=0x7ffffffff; 14 const int N=1e5+5; 15 ll mx,mi,q; 16 struct node{ 17 ll A,B,C,D,L,R; 18 }b[N]; 19 ll c[N*3]; 20 ll minv[N*12]; 21 void push(int o){ 22 minv[o]=min(minv[ls],minv[rs]); 23 } 24 void build(int o,int l,int r){ 25 if(l==r){ 26 minv[o]=1e18; 27 return; 28 } 29 int m=(l+r)/2; 30 build(ls,l,m); 31 build(rs,m+1,r); 32 push(o); 33 } 34 void up(int o,int l,int r,int p,ll v){ 35 if(l==r){ 36 minv[o]=min(minv[o],v); 37 return; 38 } 39 int m=(l+r)/2; 40 if(p<=m)up(ls,l,m,p,v); 41 else up(rs,m+1,r,p,v); 42 push(o); 43 } 44 ll qu(int o,int l,int r,int ql,int qr){ 45 if(l>=ql&&r<=qr){ 46 return minv[o]; 47 } 48 int m=(l+r)/2; 49 ll res=1e18; 50 if(ql<=m)res=min(res,qu(ls,l,m,ql,qr)); 51 if(qr>m)res=min(res,qu(rs,m+1,r,ql,qr)); 52 return res; 53 } 54 55 int main(){ 56 scanf("%d%lld",&q,&mx); 57 mi=1; 58 c[1]=mi,c[2]=mx; 59 int cnt=2; 60 for(int i=1;i<=q;i++){ 61 scanf("%lld%lld%lld%lld",&b[i].A,&b[i].B,&b[i].C,&b[i].D); 62 c[++cnt]=b[i].A; 63 c[++cnt]=b[i].B; 64 c[++cnt]=b[i].C; 65 } 66 if(mx==1){ 67 printf("0\n"); 68 return 0; 69 } 70 sort(c+1,c+1+cnt); 71 cnt=unique(c+1,c+1+cnt)-c-1; 72 for(int i=1;i<=q;i++){ 73 b[i].A=lower_bound(c+1,c+1+cnt,b[i].A)-c; 74 b[i].B=lower_bound(c+1,c+1+cnt,b[i].B)-c; 75 b[i].C=lower_bound(c+1,c+1+cnt,b[i].C)-c; 76 } 77 build(1,1,cnt); 78 up(1,1,cnt,1,0); 79 for(int i=1;i<=q;i++){ 80 ll res=qu(1,1,cnt,b[i].A,b[i].B)+b[i].D; 81 b[i].L=res; 82 up(1,1,cnt,b[i].C,res); 83 } 84 build(1,1,cnt); 85 up(1,1,cnt,cnt,0); 86 for(int i=1;i<=q;i++){ 87 ll res=qu(1,1,cnt,b[i].A,b[i].B)+b[i].D; 88 b[i].R=res; 89 up(1,1,cnt,b[i].C,res); 90 } 91 ll ans=1e18; 92 for(int i=1;i<=q;i++){ 93 ans=min(ans,b[i].L+b[i].R-b[i].D); 94 } 95 if(ans>=1e18)printf("-1\n"); 96 else printf("%lld\n",ans); 97 }