zoukankan      html  css  js  c++  java
  • [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
    ",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
    ",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;
    }

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9382784.html

  • 相关阅读:
    19凡路国庆小作业的题解集合(qwq只是我出的题,我会标明出处的)
    一个for打印99乘法表(这是一种实现方式,可以多种方式的)
    采访学长所得
    洛谷P1028 数的计算
    ccf 2019_03_2 二十四点
    ccf 201812-1 小明上学
    洛谷P3387 【模板】缩点
    洛谷P3216 [HNOI2011]数学作业
    洛谷P1471 方差
    HDU 4114 Disney's FastPass
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9382784.html
Copyright © 2011-2022 走看看