51Nod 1781 Pinball(线段树、dp、离散化)

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 #include 
 4 #define iter ::iterator
 5 using namespace  std;
 6 typedef long long ll;
 7 typedef pairP;
 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 }

 

你可能感兴趣的:(51Nod 1781 Pinball(线段树、dp、离散化))