又是一道倍增,又有线段树,又写得断断续续......

上一次……

题目链接

首先从后往前考虑每一个城市小A和小B开车会去的地方,具体来说就是将当前能到达的城市高度存进线段树,通过查找前驱后继计算出最近的城市,第二近的城市。

然后就倍增直接算了。

大概是很久没码过代码了,这样一道题居然断断续续写了几天,这样下去联赛要退役的……

/*
Author: CNYALI_LK
LANG: C++
PROG: 1081.cpp
Mail: cnyalilk@vip.qq.com
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define DEBUG printf("Passing [%s] in LINE %lld\n",__FUNCTION__,__LINE__)
#define Debug debug("Passing [%s] in LINE %lld\n",__FUNCTION__,__LINE__)
#define all(x) x.begin(),x.end()
#define x first
#define y second
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
typedef long long ll;
typedef pair<ll,ll> pii;
ll a[100005];
bool operator <(pii u,pii v){return u.x<v.x||u.x==v.x && a[u.y]<a[v.y];}
template<class T>ll chkmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>ll chkmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a>b?b:a;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
template<class T>ll dcmp(T a,T b){return a>b;}
template<ll *a>ll cmp_a(ll x,ll y){return a[x]<a[y];}
#define min mmin
#define max mmax
#define abs aabs
namespace io {
    const ll SIZE = (1 << 21) + 1;
    char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; ll f, qr;
    // getchar
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
    // prll the remaining part
    inline void flush () {
        fwrite (obuf, 1, oS - obuf, stdout);
        oS = obuf;
    }
    // putchar
    inline void putc (char x) {
        *oS ++ = x;
        if (oS == oT) flush ();
    }
    // input a signed lleger
    inline void read (ll &x) {
        for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
        for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
    }
    inline void read (char &x) {
        x=gc();
    }
    inline void read(char *x){
        while((*x=gc())=='\n' || *x==' '||*x=='\r');
        while(!(*x=='\n'||*x==' '||*x=='\r'))*(++x)=gc();
    }
    template<typename A,typename ...B>
        inline void read(A &x,B &...y){
            read(x);read(y...);
        }
    // prll a signed lleger
    inline void write (ll x) {
        if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
        while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
        while (qr) putc (qu[qr --]);
    }
    inline void write (char x) {
        putc(x);
    }
    inline void write(const char *x){
        while(*x){putc(*x);++x;}
    }
    inline void write(char *x){
        while(*x){putc(*x);++x;}
    }
    template<typename A,typename ...B>
        inline void write(A x,B ...y){
            write(x);write(y...);
        }
    //no need to call flush at the end manually!
    struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: read;
using io :: putc;
using io :: write;
const ll inf=0x7fffffff;
ll ls[3000005],rs[3000005],cnt[3000005],t; 
ll anx[21][100005],bnx[100005],as[21][100005],bs[100005],n,alls[21][100005];
void insert(ll x,ll y){
    ll r=1;
    for(ll i=30;~i;--i){
        ++cnt[r];
        if(x<(1<<i)){
            if(!ls[r])ls[r]=++t;
            r=ls[r];
        }
        else{
            if(!rs[r]){rs[r]=++t;}
            r=rs[r];
            x-=1<<i;    
        }
    }
    cnt[r]=y;
}
pii o(inf,inf);
pii pre(ll x,ll rt=1,ll t=31,ll w=0){
    if(x<w)return o;
    if(!rt)return o;
    if(!t)return make_pair(x-w,cnt[rt]);
    pii s;
    if(o!=(s=pre(x,rs[rt],t-1,w+(1LL<<(t-1)))))return s;
    return pre(x,ls[rt],t-1,w);
}
pii nxt(ll x,ll rt=1,ll t=31,ll w=0){
    if(w+(1LL<<t)<=x)return o;
    if(!rt)return o;
    if(!t)return make_pair(w-x,cnt[rt]);
    pii s;
    if(o!=(s=nxt(x,ls[rt],t-1,w)))return s;
    return nxt(x,rs[rt],t-1,w+(1LL<<(t-1)));
}
pii calc(ll s,ll x){
    pii ans(0,0);

    for(ll i=18;~i;--i){
        if(x>=alls[i][s]){
            x-=alls[i][s];
            ans.x+=as[i][s];
            ans.y+=alls[i][s]-as[i][s];
            s=anx[i][s];
        }
    }
    return ans;
}
void calc1(){
    ll x,wx=0x3f3f3f3f,wy=1,s=1;
    pii a;
    read(x);
    for(ll i=1;i<=n;++i){a=calc(i,x);if(a.x*wy<wx*a.y){wx=a.x;wy=a.y;s=i;}}
    write(s,'\n');
}
void calc2(){
    ll m,s,x;
    pii a;
    read(m);
    for(;m;--m){
        read(s,x);
        a=calc(s,x);
        write(a.x,' ',a.y,'\n');
    }
}
int main(){
#ifdef cnyali_lk
    freopen("1081.in","r",stdin);
    freopen("1081.out","w",stdout);
#endif
    t=1;
    pii Pre,Nxt;
    read(n);
    for(ll i=1;i<=n;++i){
        read(a[i]);
        a[i]+=1<<30;
    }
    ll s;
    for(ll i=n;i;--i){
        if(i==n){anx[0][i]=bnx[i]=i;as[0][i]=bs[i]=inf;}
        else{
            Pre=pre(a[i]);
            Nxt=nxt(a[i]);
            if(i==n-1){anx[0][i]=i;bnx[i]=min(Pre,Nxt).y;as[0][i]=inf;bs[i]=min(Pre,Nxt).x;}
            else{
                if(Nxt<Pre){
                    bnx[i]=Nxt.y;
                    bs[i]=Nxt.x;
                    s=(a[Nxt.y]+1-a[i]);
                    Nxt=nxt(a[Nxt.y]+1);
                    Nxt.x+=s;
                }
                else{
                    bnx[i]=Pre.y;
                    bs[i]=Pre.x;
                    s=(a[i]-a[Pre.y]+1);
                    Pre=pre(a[Pre.y]-1);
                    Pre.x+=s;
                }
                if(Nxt<Pre)Pre=Nxt;
                anx[0][i]=Pre.y;
                as[0][i]=Pre.x;
            }
        }
        alls[0][i]=as[0][i];
//        write(anx[0][i],' ',as[0][i],' ',alls[0][i],' ',bnx[i],' ',bs[i],'\n');
        insert(a[i],i);
    }
    for(ll i=1;i<=n;++i){
        anx[1][i]=bnx[anx[0][i]];
        as[1][i]=as[0][i];
        alls[1][i]=as[0][i]+bs[anx[0][i]];
    }
    for(ll i=2;i<=18;++i){
        for(ll j=1;j<=n;++j){
            alls[i][j]=alls[i-1][j]+alls[i-1][anx[i-1][j]];
            as[i][j]=as[i-1][j]+as[i-1][anx[i-1][j]];
            anx[i][j]=anx[i-1][anx[i-1][j]];
        }
    }
    calc1();
    calc2();
    return 0;
}

标签: 线段树, 倍增

添加新评论