zoukankan      html  css  js  c++  java
  • BZOJ3642 : [CEOI 2014] Cake

    rank[i]表示第i美味的是哪块

    left[i]表示在k左边美味度为i的是哪块

    right[i]表示在k右边美味度为i的是哪块

    用3棵线段树分别维护d序列的区间最大值、left序列的区间最大值、right序列的区间最小值

    修改:

    把第x块改成第y美味

    把第y+1到第9美味的全部后移一位

    然后把第x块美味度改成最大值+1

    然后把第y-1到第1美味的美味度依次改成最大

    查询:

    设x到k这一段中美味度的最大值为y

    求出k另一侧最靠近k的且美味度大于y的位置z

    答案为|z-x|-1

    时间复杂度为每次操作$O(log n)$

    一开始写了普通线段树被卡常数了TAT(最近怎么都被卡常数)

    然后去学了zkw线段树后改成zkw线段树就过了,效果拔群,又快又短。

    zkw线段树真是个好东西。

    #include<cstdio>
    const int N=250010,inf=~0U>>1;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline int min(int a,int b){return a<b?a:b;}
    inline int max(int a,int b){return a>b?a:b;}
    inline void Max(int&a,int b){if(a<b)a=b;}
    inline void Min(int&a,int b){if(a>b)a=b;}
    int n,m,t,q,k,i,x,y,rank[N],d[N],left[5250010],right[5250010],M1,M2,ta_v[530000],tl_v[16777220],tr_v[16777220],que[500010][3];
    char ch;
    inline void ta_change(int x,int y){for(ta_v[x+=M1]=y,x>>=1;x;x>>=1)ta_v[x]=max(ta_v[x<<1],ta_v[x<<1|1]);}
    inline int ta_ask(int x,int y){
      int t=-inf;
      for(x+=M1-1,y+=M1+1;x^y^1;x>>=1,y>>=1){
        if(~x&1)Max(t,ta_v[x^1]);
        if(y&1)Max(t,ta_v[y^1]);
      }
      return t;
    }
    inline void tl_change(int x,int y){for(tl_v[x+=M2]=y,x>>=1;x;x>>=1)tl_v[x]=max(tl_v[x<<1],tl_v[x<<1|1]);}
    inline int tl_ask(int x,int y){
      int t=-inf;
      for(x+=M2-1,y+=M2+1;x^y^1;x>>=1,y>>=1){
        if(~x&1)Max(t,tl_v[x^1]);
        if(y&1)Max(t,tl_v[y^1]);
      }
      return t;
    }
    inline void tr_change(int x,int y){for(tr_v[x+=M2]=y,x>>=1;x;x>>=1)tr_v[x]=min(tr_v[x<<1],tr_v[x<<1|1]);}
    inline int tr_ask(int x,int y){
      int t=inf;
      for(x+=M2-1,y+=M2+1;x^y^1;x>>=1,y>>=1){
        if(~x&1)Min(t,tr_v[x^1]);
        if(y&1)Min(t,tr_v[y^1]);
      }
      return t;
    }
    inline void modify(int x,int y){//d[x]改成y
      if(x<k)tl_change(d[x],0);
      if(x>k)tr_change(d[x],n+1);
      ta_change(x,d[x]=y);
      if(x<k)tl_change(y,x);
      if(x>k)tr_change(y,x);
    }
    inline void change(int x,int y){//把第x块蛋糕设置成第y美味
      int i,j=0;
      for(i=1;i<=10;i++)if(rank[i]==x)j=i;
      for(i=j?j:10;i>y;i--)rank[i]=rank[i-1];
      for(modify(rank[y]=x,++t),i=y-1;i;i--)modify(rank[i],++t);
    }
    inline int ask(int x){
      if(x==k)return 0;
      return x<k?tr_ask(ta_ask(x,k-1)+1,m)-x-1:x-tl_ask(ta_ask(k+1,x)+1,m)-1;
    }
    int main(){
      read(n),read(k);
      for(i=1;i<=n;i++)read(d[i]),rank[n-d[i]+1]=i;
      read(q);
      m=(t=n)+1;
      for(i=1;i<=q;i++){
        while(!(((ch=getchar())=='E')||(ch=='F')));
        if(ch=='E')read(que[i][1]),read(que[i][2]),m+=que[i][2];else que[i][0]=1,read(que[i][1]);
      }
      for(i=1;i<=m;i++)right[i]=n+1;
      for(i=1;i<k;i++)left[d[i]]=i;
      for(i=k+1;i<=n;i++)right[d[i]]=i;
      for(M1=1;M1<n+2;M1<<=1);
      for(i=1;i<=n;i++)ta_v[i+M1]=d[i];
      for(i=M1-1;i;i--)ta_v[i]=max(ta_v[i<<1],ta_v[i<<1|1]);
      for(M2=1;M2<m+2;M2<<=1);
      for(i=1;i<=m;i++)tl_v[i+M2]=left[i],tr_v[i+M2]=right[i];
      for(i=M2-1;i;i--)tl_v[i]=max(tl_v[i<<1],tl_v[i<<1|1]),tr_v[i]=min(tr_v[i<<1],tr_v[i<<1|1]);
      for(i=1;i<=q;i++)if(!que[i][0])change(que[i][1],que[i][2]);else printf("%d
    ",ask(que[i][1]));
      return 0;
    }
    

      

  • 相关阅读:
    B-Tree索引的学习记录
    mysql NOW,CURRENT_TIMESTAMP,SYSDATE 之间的区别
    哈希索引
    MyISAM和InnoDB的区别
    负载均衡记录一
    哈希索引
    mysql ZEROFILL属性
    redis常用命令及使用场景
    js Function()构造函数
    书写闭包的时候需注意一下情况
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403231.html
Copyright © 2011-2022 走看看