51NOD1781 Pinball 【离散化+线段树】
来源:互联网 发布:淘宝店不开了怎么注销 编辑:程序博客网 时间:2024/06/06 02:05
1781 Pinball
基准时间限制:1 秒 空间限制:262144 KB 分值: 20 难度:3级算法题
Pinball的游戏界面由m+2行、n列组成。第一行在顶端。一个球会从第一行的某一列出发,开始垂直下落,界面上有一些漏斗,一共有m个漏斗分别放在第2~m+1行,第i个漏斗的作用是把经过第i+1行且列数在Ai~Bi之间的球,将其移到下一行的第Ci列。 使用第i个漏斗需要支付Di的价钱,你需要保留一些漏斗使得球无论从第一行的哪一列开始放,都只可能到达第m+2行的唯一 一列,求花费的最少代价。
(样例的图)
(我们保留2,4,5即可,代价为5+3+12=20)
Input
第一行两个数,m和n。m<=100000,2<=n<=1000000000
接下来m行,第i+1行描述第i个漏斗的属性,Ai,Bi,Ci,Di (1<=Ai<=Ci<=Bi<=n, 1<=Di<=1000000000)。
Output
若不存在一种方案能满足条件则输出-1,否则输出最小花费
Input示例
5 6
3 5 4 8
1 4 3 5
4 6 5 7
5 6 5 3
3 5 4 12
Output示例
20
xfause (题目提供者)
首先 需要发现 对任意一种漏斗组合
设to[i] = 从第i列扔下小球 小球最终掉落的位置
对任意i < j ,必定有 to[i] <= to[j]
所以 如果 to[1]==to[m] 小球从任意位置掉落 都到 to[1] 位置上
所以 问题转化为 使1和m位置扔下的小球 落在同样位置
不难发现 花销最小时 1和m扔出的球 都会经过最后一个漏斗 且 在之前 不会经过相同的漏斗
oneTo[i] = 从1扔出 经过第i个漏斗 需要的最少花费
mTo[i] = 从m扔出 经过i漏斗 的最少花费
所以 答案就 = min( oneTo[i] + mTo[i] - d[i] )
于是问题就转化为求oneTo[i] 和 mTo[i]
显然
oneTo[i] = min( oneTo[j] ) + d[i] //其中a[i]<=c[j]<=b[i] 且 j < noneTo[i] = d[i] //a[i]==1
复杂度为O(n*n) 显然不理想
此处如果使用线段树 维护 从1扔出小球 从 [ posL,posR ] 位置掉出 的最小花销
每次查询O(log(n) )
于是复杂度为O(nlog(n) )
PS:显然m过大 果断离散化
#include<iostream>#include<stdlib.h>#include<stdio.h>#include<string>#include<vector>#include<deque>#include<queue>#include<algorithm>#include<set>#include<map>#include<stack>#include<time.h>#include<math.h>#include<list>#include<cstring>#include<fstream>#include<queue>#include<sstream>//#include<memory.h>using namespace std;#define ll long long#define ull unsigned long long#define pii pair<int,int>#define INF 1000000007#define pll pair<ll,ll>#define pid pair<int,double>const ll inf = 1e17;const int N = 100000 + 5;const int M = 3*N;int read(){ char c=getchar();int k=0;for (;c<48||c>57;c=getchar()); for (;c>47&&c<58;c=getchar()) k=(k<<3)+(k<<1)+c-48;return k;}ll rmq[M*4];//从[l,r]列掉下一个小球的最少花费int pot[N][4];struct ColHash{ int key,i,j;}colHash[3*N];bool operator<(const ColHash&a,const ColHash&b){ return a.key<b.key;}int Hash(int n,int m){//返回离散化后的列数 colHash[3*n]={1,-1,-1}; colHash[3*n+1]={m,-1,-1}; for(int i=0;i<n;++i){ for(int j=0;j<3;++j){ colHash[3*i+j]={pot[i][j],i,j}; } } sort(colHash,colHash+3*n+2); int k=0; for(int i=0;i<3*n+2;++i){ if(i==0||colHash[i].key!=colHash[i-1].key){ ++k; } if(colHash[i].i!=-1){ pot[colHash[i].i][colHash[i].j]=k; } } return k;}void initRmq(int k,int l,int r){ rmq[k]=inf; if(l!=r){ int mid = (l+r)/2; initRmq(2*k+1,l,mid); initRmq(2*k+2,mid+1,r); }}void addNode(int k,int l,int r,int pos,ll v){ if(l<=pos&&pos<=r){ rmq[k]=min(rmq[k],v); if(l!=r){ int mid=(l+r)/2; if(pos<=mid){ addNode(2*k+1,l,mid,pos,v); } if(pos>=mid+1){ addNode(2*k+2,mid+1,r,pos,v); } } }}ll query(int k,int l,int r,int posL,int posR){ if(posL<=l&&r<=posR){ return rmq[k]; } ll ans=inf; if(l!=r){ int mid=(l+r)/2; if(mid>=posL){ ll tmp = query(2*k+1,l,mid,posL,posR); ans=min(tmp,ans); } if(mid+1<=posR){ ll tmp=query(2*k+2,mid+1,r,posL,posR); ans=min(tmp,ans); } } return ans;}ll oneTo[N];//从第1列扔下 到穿过第i个漏斗 的最少花销ll mTo[N];//从第m列扔下 .....ll dp(int n,int m){ fill(oneTo,oneTo+n+1,inf); initRmq(0,1,m); addNode(0,1,m,1,0);//从1扔下 花销0 for(int i=0;i<n;++i){ ll val = query(0,1,m,pot[i][0],pot[i][1]); oneTo[i]=min(oneTo[i],pot[i][3]+val); addNode(0,1,m,pot[i][2],oneTo[i]); } fill(mTo,mTo+n+1,inf); initRmq(0,1,m); addNode(0,1,m,m,0); for(int i=0;i<n;++i){ ll val = query(0,1,m,pot[i][0],pot[i][1]); mTo[i]=min(mTo[i],pot[i][3]+val); addNode(0,1,m,pot[i][2],mTo[i]); } ll ans =inf; for(int i=0;i<n;++i){ ans = min(ans,oneTo[i]+mTo[i]-pot[i][3]); } return ans>=inf?-1:ans;}int main(){ //freopen("/home/lu/Documents/r.txt","r",stdin); //freopen("/home/lu/Documents/w.txt","w",stdout); int n=read(),m=read(); //scanf("%d%d",&n,&m); for(int i=0;i<n;++i){ for(int j=0;j<4;++j){ pot[i][j]=read(); } } m=Hash(n,m); printf("%lld\n",dp(n,m)); return 0;}
- 51NOD1781 Pinball 【离散化+线段树】
- 51nod 1781 Pinball【DP】【线段树】
- 线段树+离散化
- 离散化 + 线段树
- 线段树离散化
- 线段树离散化
- POJ_2528 线段树+离散化
- HDU3577 离散化+线段树
- poj2528 线段树+离散化
- poj2528线段树+离散化
- hdu4325线段树+离散化
- POJ2528 离散化线段树
- 【线段树+离散化】Cover
- poj2482 离散化+线段树
- poj2528_线段树+离散化
- poj1151(线段树+离散化)
- hdu3743(线段树+离散化)
- 数据离散化 & 线段树
- 特征点检测学习_2(surf算法)
- Android View事件分发、拦截、消费机制
- Volley的简单应用
- 位运算操作
- Jenkins-Build Monitor View
- 51NOD1781 Pinball 【离散化+线段树】
- poj_1639 Picnic Planning(度限制最小生成树)
- hadoop2.6.0伪分布式环境搭建
- Android侧滑菜单——SlidingMenu详解使用
- IO流实现文件的读写(图像、音频、视频)
- 数据库SQL语言语法总结3---查询语句
- MySQL的增删改查
- 自定义ContentProvider的简单增删除改
- 位运算在用户权限管理中的应用