[LUOGU] P1081 开车旅行

终于告一段落了。

需要快速求出(logn级别)的量是每个点往后不超过x长度,A和B能开的长度和到达的点。

用f[i][j]表示点i开始,往后两人开2^j次到达的点,A[i][j]和B[i][j]分别表示两人从i开始开2^j次行驶的距离

然后用类似倍增求LCA的思路,由大往小逼近即可求出指定解。

对于问题1,需要n次logn的查询,对于问题2,需要m次logn的查询,总复杂度在O((n+m)logn)

问题是,如何求这个倍增数组?

先考虑求j=0时,我们要求出每个点的前驱和后继才能方便判断,就想到了建一颗平衡树,倒着加点,同时更新每个点的最近点和次近点(根据题目定义,向下靠拢)

这样就可以方便地倍增啦!

然而,题解中有更好的方法求前驱后继,待我研究一下..

是这样的,我们需要求前驱,后继,大概是两位的距离,而且可以离线,所以可以把原数组排序,用双向链表串起来,可以方便找前两个和后两个,也可以方便地删除..

预处理复杂度也是在O(nlogn)的

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define check(x) (x==ch[fa[x]][1])
#define clear(x) val[x]=cnt[x]=siz[x]=ch[x][0]=ch[x][1]=fa[x]=0
#define pushup(x) siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x]
#define R register int
#define int long long
using namespace std;

const int MAXN=400005;
const int INF=1ll<<50;

int val[MAXN],cnt[MAXN],siz[MAXN];
int ch[MAXN][2],fa[MAXN];
int tot,root;
inline int newnode(int x){cnt[++tot]++;siz[tot]=1;val[tot]=x;return tot;}
void rotate(int x){
  int y=fa[x],z=fa[fa[x]];
  bool ck=check(x);
  fa[ch[x][ck^1]]=y;ch[y][ck]=ch[x][ck^1];
  ch[x][ck^1]=y;fa[y]=x;fa[x]=z;
  if(z) ch[z][ch[z][1]==y]=x;
  pushup(y);pushup(x);
}
void splay(int x){
  for(R f=fa[x];f;rotate(x),f=fa[x])
    if(fa[f]) rotate(check(f)==check(x)?f:x);
  root=x;
}
void insert(int x){
  if(!root){root=newnode(x);return;}
  int cur=root,f=0;
  while(1){
    if(val[cur]==x){cnt[cur]++;pushup(cur);pushup(f);splay(cur);return;}
    f=cur;cur=ch[cur][x>val[cur]];
    if(!cur){cur=newnode(x);fa[cur]=f;ch[f][x>val[f]]=cur;pushup(f);splay(cur);return;}
  }
}
int rk(int x){
  int cur=root,ret=0;
  while(1){
    if(x<val[cur]) cur=ch[cur][0];
    else{
      ret+=siz[ch[cur][0]];
      if(val[cur]==x) return splay(cur),ret+1;//
      ret+=cnt[cur];cur=ch[cur][1];
    }
  }
}
int kth(int x){
  int cur=root;
  while(1){
    if(ch[cur][0]&&x<=siz[ch[cur][0]]) cur=ch[cur][0];
    else{
      x-=siz[ch[cur][0]]+cnt[cur];
      if(x<=0) return cur;
      cur=ch[cur][1];
    }
  }
}
int prev(){
  int cur=ch[root][0];
  while(ch[cur][1]) cur=ch[cur][1];
  return cur;
}
int nxtv(){
  int cur=ch[root][1];
  while(ch[cur][0]) cur=ch[cur][0];
  return cur;
}
void del(int x){
  rk(x);
  if(cnt[root]>1){cnt[root]--;pushup(root);return;}
  if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;}
  if(!ch[root][0]){int sav=root;root=ch[sav][1];fa[root]=0;clear(sav);return;}
  if(!ch[root][1]){int sav=root;root=ch[sav][0];fa[root]=0;clear(sav);return;}
  int sav=root;
  splay(prev());
  ch[root][1]=ch[sav][1];
  fa[ch[sav][1]]=root;
  clear(sav);
  pushup(root);
}
int pre(int x){
    insert(x);int ret=prev();
    del(x);return val[ret];
}
int nxt(int x){
    insert(x);int ret=nxtv();
    del(x);return val[ret];
}
int n,m;
inline int rd(){
  int ret=0,f=1;char c;
  while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
  while(isdigit(c))ret=ret*10+c-'0',c=getchar();
  return ret*f;
}

map<int,int> mp;
int h[MAXN];
int aim[MAXN][2];

int f[MAXN][32],A[MAXN][32],B[MAXN][32];
int LEN;

void solve1(){
    int X0,sa,sb,fans;
    X0=rd();
    int pos,sav=0;
    long double tmp,ans=1e9;
    for(R i=1;i<=n;i++){
        pos=i;sav=0;sa=0;sb=0;
        for(R j=LEN;j>=0;j--){
            if(f[pos][j]>n||f[pos][j]==0) continue;//==0
            if(sav+A[pos][j]+B[pos][j]>X0) continue;
            sa+=A[pos][j];sb+=B[pos][j];
            sav+=A[pos][j]+B[pos][j];
            pos=f[pos][j];
        }
        tmp=sa==0?1e9:1.0*sb/sa;
        if(tmp<ans){ans=tmp;fans=i;}
        else if(tmp==ans) fans=h[fans]>h[i]?fans:i;
    }
    printf("%d\n",fans);
}

void solve2(){
    int x,y;
    x=rd();y=rd();
    int pos=x;
    long long sav=0;
    long long ans1=0,ans2=0;
    for(R j=LEN;j>=0;j--){
        if(f[pos][j]>n||f[pos][j]==0) continue;//
        if(sav+A[pos][j]+B[pos][j]>y) continue;
        ans1+=B[pos][j];ans2+=A[pos][j];
        sav+=A[pos][j]+B[pos][j];
        pos=f[pos][j];
    }
    printf("%lld %lld\n",ans1,ans2);
}

int main(){
  n=rd();LEN=log2(n);
  insert(INF);insert(-INF);
  for(R i=1;i<=n;i++) h[i]=rd(),mp[h[i]]=i;
  for(R i=n;i>=1;i--){
      int pr=pre(h[i]),nx=nxt(h[i]),ppr=-INF,nnx=INF,tmp=INF;
    aim[i][0]=h[i]-pr<=nx-h[i]?pr:nx;
      if(pr!=-INF) ppr=pre(pr);if(nx!=INF) nnx=nxt(nx);
      int t=0,po=0;
      if(nx==aim[i][0]) t++,po=nx;
      if(nnx==aim[i][0]) t++,po=nnx;
      if(pr==aim[i][0]) t++,po=pr;
      if(ppr==aim[i][0]) t++,po=ppr;
      if(nx-h[i]<tmp&&nx!=aim[i][0]) tmp=nx-h[i],aim[i][1]=nx;
      if(nnx-h[i]<tmp&&nnx!=aim[i][0]) tmp=nnx-h[i],aim[i][1]=nnx;
      if(h[i]-pr<=tmp&&pr!=aim[i][0]) tmp=h[i]-pr,aim[i][1]=pr;
      if(h[i]-ppr<=tmp&&ppr!=aim[i][0]) tmp=h[i]-ppr,aim[i][1]=ppr;
      if(t>=2) aim[i][1]=po;
      insert(h[i]);
  }
  for(R i=1;i<=n;i++)
      for(R j=0;j<=1;j++)
      aim[i][j]=mp[aim[i][j]];
}
  for(R i=1;i<=n;i++){
      f[i][0]=aim[i][1];
      f[i][1]=aim[aim[i][1]][0];
      B[i][0]=B[i][1]=abs(h[f[i][0]]-h[i]);
      A[i][1]=abs(h[f[i][0]]-h[f[i][1]]);
      A[i][0]=0;
  }
  for(R j=2;(1<<j)<=n;j++){
      for(R i=1;i<=n;i++){
          f[i][j]=f[f[i][j-1]][j-1];
          A[i][j]=A[i][j-1]+A[f[i][j-1]][j-1];
          B[i][j]=B[i][j-1]+B[f[i][j-1]][j-1];
      }
  }
  solve1();
  m=rd();
  while(m--) solve2();
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/ghostcai/p/9382784.html