P1081 开车旅行 倍增 洛谷
2018-03-17 12:18
344 查看
题目连接
在这里注意一点,就是当差值最小的两个值相等的时候,小B走的是海拔较低的那个点,涉及到第二关键字的问题,我们可以用一个比较省事的方法,那就是给海拔低的点计算差值时候乘以99999999,海拔较高的点计算差值时候乘以100000000。
nxt2[i]nxt2[i]代表从ii出发,小A的目的地。
nxt3[i][j]nxt3[i][j]代表从ii出发,(小A走完、小B走完)2j2j轮,所达到的目的
地。
DP1[i][j]DP1[i][j]代表从i出发,(小A走完、小B走完)2j2j轮,小B所经过的距离。
DP2[i][j]DP2[i][j]代表从i出发,(小A走完、小B走完)2j2j轮,小A所经过的距离。
nxt3,DP1,DP2可以用类似于处理ST表的方法求出来。
从S出发,走len轮,返回ans1为小B走过的路程,返回ans2为小A走过的路程,并且把S改变为len轮以后到达的点。
从S出发,总路程不能超过X,返回最大能走几轮。
题意
题目已经说的hin明确了。题解
我们要求出从每个点出发,小A要走的城市和小B要走的城市。
我们把ii以后的所有点的海拔加入到setset,然后拿H[i]H[i]到set里面去lower_bound,找到比H[i]大的两个地点和比H[i]小的两个地点,并把这四个地点与H[i]的差值加入到新的排序数组中,排个序,找到差值最小的两个点,分别就是小B要选的目的地和小A要选的目的地。在这里注意一点,就是当差值最小的两个值相等的时候,小B走的是海拔较低的那个点,涉及到第二关键字的问题,我们可以用一个比较省事的方法,那就是给海拔低的点计算差值时候乘以99999999,海拔较高的点计算差值时候乘以100000000。
定义需要的状态
nxt1[i]nxt1[i]代表从ii出发,小B的目的地。nxt2[i]nxt2[i]代表从ii出发,小A的目的地。
nxt3[i][j]nxt3[i][j]代表从ii出发,(小A走完、小B走完)2j2j轮,所达到的目的
地。
DP1[i][j]DP1[i][j]代表从i出发,(小A走完、小B走完)2j2j轮,小B所经过的距离。
DP2[i][j]DP2[i][j]代表从i出发,(小A走完、小B走完)2j2j轮,小A所经过的距离。
nxt3,DP1,DP2可以用类似于处理ST表的方法求出来。
函数解释
一轮代表小A走一次+小B走一次。getdp(int &S,int len,ll &ans1,ll &ans2)
从S出发,走len轮,返回ans1为小B走过的路程,返回ans2为小A走过的路程,并且把S改变为len轮以后到达的点。
getmx(int S,ll X)
从S出发,总路程不能超过X,返回最大能走几轮。
回答询问
给出SiSi和XiXi,用二分的方法求出从Si出发小A和小B最长能走的长度。代码
// luogu-judger-enable-o2 #include <iostream> #include <cstdio> #include <algorithm> #include <set> using namespace std; typedef long long ll; typedef pair<ll,int> pll; set<pll>::iterator it; const int maxn = 500007; int nxt1[maxn],nxt2[maxn],nxt3[maxn][30]; int N,LOG,X0,M; ll H[maxn],H2[maxn],H1[maxn],DP2[maxn][30],DP1[maxn][30]; pll tmpsort[7]; void getdp(int &S,int len,ll &ans1,ll &ans2){ int cnt = 0; while(len){ if(len & 1){ ans1 += DP1[S][cnt]; ans2 += DP2[S][cnt]; S = nxt3[S][cnt]; } len >>= 1; cnt++; if(!S) break; } return ; } int getmx(int S,ll X){ int l = 0,mid,r = N+1; while(r - l > 1){ mid = (l+r)/2; int nS = S; ll ans1 = 0,ans2 = 0; getdp(nS,mid,ans1,ans2); if(ans1+ans2 > X || !nS) r = mid; else l = mid; } return l; } int main(){ set<pll> st; cin>>N; int tmp = 1; while(tmp <= N/3) LOG++,tmp <<= 1; for(int i = 1;i <= N;++i){ scanf("%lld",&H[i]); st.insert(make_pair(H[i],i)); } for(int i = 1;i < N;++i){ int ct = 0; st.erase(make_pair(H[i],i)); it = st.lower_bound(make_pair(H[i],i)); if(it != st.end()){ tmpsort[ct++] = make_pair(abs(H[i]-(*it).first)*100000000,(*it).second); ++it; } if(it != st.end()){ tmpsort[ct++] = make_pair(abs(H[i]-(*it).first)*100000000,(*it).second); } it = st.lower_bound(make_pair(H[i],i)); if(it != st.begin()) { --it; tmpsort[ct++] = make_pair(abs(H[i]-(*it).first)*99999999,(*it).second); if(it != st.begin()){ --it; tmpsort[ct++] = make_pair(abs(H[i]-(*it).first)*99999999,(*it).second); } } sort(tmpsort,tmpsort+ct); if(ct > 0) nxt1[i] = tmpsort[0].second; if(ct > 1) nxt2[i] = tmpsort[1].second; } for(int i = 1;i < N;++i) nxt3[i][0] = nxt1[nxt2[i]]; for(int i =1;i <= N;++i){ if(nxt1[i]) H1[i] = abs(H[nxt1[i]] - H[i]); if(nxt2[i]){ H2[i] = abs(H[nxt2[i]] - H[i]); DP2[i][0] = abs(H[nxt2[i]] - H[i]); } if(nxt1[nxt2[i]]) DP1[i][0] = abs(H[nxt1[nxt2[i]]] - H[nxt2[i]]); } for(int j = 1;j <= LOG;++j){ for(int i = 1;i <= N;++i){ nxt3[i][j] = nxt3[nxt3[i][j-1]][j-1]; DP1[i][j] = DP1[i][j-1] + DP1[nxt3[i][j-1]][j-1]; DP2[i][j] = DP2[i][j-1] + DP2[nxt3[i][j-1]][j-1]; } } int mf1 = 0,mf2 = 1,mh = 0; int ans1 = 1; cin>>X0>>M; for(int i = 1;i <= N;++i){ ll f1 = 0,f2 = 0; int nS = i; int mxl = getmx(i,X0); getdp(nS,mxl,f1,f2); if(nxt2[nS] && H2[nS]+f1+f2 <= X0) f2 += H2[nS]; if(!f2) continue; if(mf1*f2 < f1*mf2){ mf1 = f1; mf2 = f2; ans1 = i; mh = H[i]; } else if(mf1*f2 == mf2*f1 && H[i] > mh){ mf1 = f1; mf2 = f2; ans1 = i; mh = H[i]; } } cout<<ans1<<endl; for(int i = 0;i < M;++i){ int Si,nSi;ll Xi; scanf("%d %lld",&Si,&Xi); nSi = Si; int mxl = getmx(Si,Xi); ll f1 = 0,f2 = 0; getdp(nSi,mxl,f1,f2); if(nxt2[nSi] && H2[nSi]+f1+f2 <= Xi) f2 += H2[nSi]; printf("%lld %lld\n",f2,f1); } return 0; }
相关文章推荐
- 洛谷P1081:开车旅行 (Treap+倍增)
- 洛谷 P1081 开车旅行 [noip2012] (倍增lca+链表优化)
- 洛谷 P1081 开车旅行
- 洛谷P1081 开车旅行
- 洛谷1081/codevs1199 开车旅行 链表,倍增,模拟
- [NOIP2012] 提高组 洛谷P1081 开车旅行
- 洛谷 P1081 开车旅行【双向链表+倍增】
- 洛谷 P1081 开车旅行(抄)
- 洛谷 P1081开车旅行
- 【luogu1081】开车旅行(倍增)
- NOIP2012 开车旅行 倍增与模拟结合后的调试神题
- codevs1199开车旅行[倍增] 留坑
- noip2012 开车旅行 (倍增处理)
- Vijos P1780 开车旅行 (倍增+Treap)
- Noip 2012 开车旅行(倍增思想的活用)
- 【倍增】【set】[NOIP2012] codevs1199 开车旅行
- 开车旅行 2012年NOIP全国联赛提高组(倍增+set)
- 【noip】开车旅行 平衡树 倍增 treap tree
- NOIP2012 开车旅行 (倍增)
- noip2012 P1081 开车旅行