LUOGU P1081 开车旅行 (noip 2012)

传送门

解题思路

这道题刚了一下午,主要就刚在set那里了。先写了一个暴力70分。。之后优化预处理,看着大佬神犇们都用的什么双向链表之类的东西,本蒟蒻不会,又懒得手写平衡树,就拿了个set搞了搞,感觉做麻烦了,我开了两个set,一个存正数一个存负数。因为STL只能求后继,然后每次先求最小,删掉再求次小,再加回来。预处理复杂度应该是nlogn,交了一发75,看了看lyd的书才知道要倍增。f[i][j][0/1]表示一共走了2^i天,在j这个城市,轮A/B开车的到达的城市,如果i=1 f[i][j][k]=f[i-1][f[i-1][j][k]][1-k],意思就是走了2天,一人开了一天,所以由另一个人最后开转移来。如果i>1 f[i][j][k]=f[i-1][f[i-1][j][k]][k], 意思是每个人开了偶数天,所以前后两半的最后都是同一个人开,再预处理一个data表示路程,处理方法和f相近,最后卡了卡常。。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>

using namespace std;
const int MAXN = 100005;
typedef long long LL;

inline LL rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

struct Pos{
    int id;
    LL high;
}pos[MAXN],rev[MAXN];

int n,m,nxt[MAXN][3],x0,st,f[22][MAXN][2];
LL ans[3],dis[MAXN][3],data[22][MAXN][2][2];
double K=1e9;
set<Pos> S,T;
bool operator <(const Pos &A,const Pos &B){
    return A.high<B.high;
}

int main(){
//  freopen("random.txt","r",stdin);
//  freopen("A.txt","w",stdout);
    n=rd();int lg=log2(n);
    for(register int i=1;i<=n;i++) pos[i].high=rd(),pos[i].id=i;
    for(register int i=n;i;i--){
        rev[i].high=-pos[i].high;rev[i].id=i;
        LL mn1=1e18,mn2=1e18;int p1=-1,p2=-1;Pos A;int flag=0;
        set<Pos>::iterator it=S.lower_bound(pos[i]);
        if(it!=S.end()) {mn1=abs((*it).high-pos[i].high);p1=(*it).id;A=*it;flag=1;}
        it=T.upper_bound(rev[i]);
        if(it!=T.end() && abs(-((*it).high)-pos[i].high)<=mn1){
            mn1=abs(-((*it).high)-pos[i].high);
            p1=(*it).id;A=*it;flag=2;
        }
        Pos B;B.id=A.id;B.high=-A.high;
        if(flag==1) S.erase(A),T.erase(B);
        else if(flag==2) S.erase(B),T.erase(A);
        if(flag){
            it=S.lower_bound(pos[i]);   
            if(it!=S.end()) {mn2=abs((*it).high-pos[i].high);p2=(*it).id;}
            it=T.upper_bound(rev[i]);
            if(it!=T.end() && abs(-((*it).high)-pos[i].high)<=mn2){
                mn2=abs(-((*it).high)-pos[i].high);
                p2=(*it).id;
            }
        }
        if(flag==1) S.insert(A),T.insert(B);
        else if(flag==2) S.insert(B),T.insert(A);
        S.insert(pos[i]);T.insert(rev[i]);
        nxt[i][1]=p2,nxt[i][2]=p1;
        dis[i][1]=mn2,dis[i][2]=mn1;
//      cout<<i<<" "<<nxt[i][2]<<" "<<dis[i][2]<<endl;
        f[0][i][0]=nxt[i][1];
        f[0][i][1]=nxt[i][2];
        data[0][i][0][0]=dis[i][1];
        data[0][i][1][0]=0;
        data[0][i][0][1]=0;
        data[0][i][1][1]=dis[i][2];     
    }
    for(register int i=1;i<=lg;i++)
        for(register int j=1;j<=n;j++)
            for(register int k=0;k<=1;k++){
                if(i==1){
                    f[1][j][k]=f[0][f[0][j][k]][1-k];
                    data[1][j][k][0]=data[0][j][k][0]+data[0][f[0][j][k]][1-k][0];
                    data[1][j][k][1]=data[0][j][k][1]+data[0][f[0][j][k]][1-k][1];
                    continue;
                }
                f[i][j][k]=f[i-1][f[i-1][j][k]][k];
                data[i][j][k][0]=data[i-1][j][k][0]+data[i-1][f[i-1][j][k]][k][0];
                data[i][j][k][1]=data[i-1][j][k][1]+data[i-1][f[i-1][j][k]][k][1];
            }
    x0=rd();
    for(register int i=1;i<=n;i++){
        ans[1]=ans[2]=0;int p=i;
        for(register int j=lg;j>=0;j--)
            if(ans[1]+ans[2]+data[j][p][0][0]+data[j][p][0][1]<=x0){
                ans[1]+=data[j][p][0][0];ans[2]+=data[j][p][0][1];
                p=f[j][p][0];
            }
        if(ans[2]==0) {if(K==1e9 && pos[i].high>pos[st].high) st=i;continue;}
        if((double)ans[1]/ans[2]<K || ((double)ans[1]/ans[2]==K && pos[i].high>pos[st].high)){
            st=i;
            K=(double)ans[1]/ans[2];
        }
    }
    printf("%d\n",st);
    m=rd();
    for(register int i=1;i<=m;i++){ 
        LL x=rd(),y=rd();
        ans[1]=ans[2]=0;int p=x;
        for(register int j=lg;j>=0;j--)
            if(ans[1]+ans[2]+data[j][p][0][0]+data[j][p][0][1]<=y){
                ans[1]+=data[j][p][0][0];ans[2]+=data[j][p][0][1];
                p=f[j][p][0];
            }
        printf("%lld %lld\n",ans[1],ans[2]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值