Description

给定一个含有n个数的序列a1,a2,a3an,程序必须回答这样的询问:对于给定的i,j,k,在ai,ai+1,ai+2aj中第k小的数是多少(1kji+1),并且,你可以改变一些ai的值,改变后,程序还能针对改
变后的a继续回答上面的问题。

Input

第一行有两个正整数n(1n10000)m(1m10000)
分别表示序列的长度和指令的个数。
第二行有n个数,表示a1,a2an,这些数都小于109
接下来的m行描述每条指令。
每行的格式是下面两种格式中的一种。
Q i j k 或者 C i t
Q i j ki,j,k是数字,1ijn,1kji+1)表示询问指令,询问ai,ai+1aj中第k小的数。
C i t(1in,0t109)表示把ai改变成为t
m,n10000

Output

对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

Sample Input

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

Sample Output

3
6

HINT

Source

思路

位置线段树套权值splay;
这里两个操作Q和C,C的话把位置线段树上每一个包含i的区间全部增加一个节点j减去一个节点ai,然后把ai改成j
Q操作是重点:二分答案,在位置线段树上的[i,j]区间找比二分出来的mid小的个数,如果小于k,则缩小right,否则left增加。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
整体二分写法:
二分答案区间,将询问与修改一起二分(分流)。

代码(树套树版)

#include <cstdio>
#include <iostream>

const int maxn=10000;
const int maxs=4000000;

int a[maxn+10];

struct splay_tree//权值splay
{
  int fa[maxs+10],son[2][maxs+10],size[maxs+10],val[maxs+10],tot;

  inline int t(int x)
  {
    return son[1][fa[x]]==x;
  }

  inline int updata(int x)
  {
    return size[x]=size[son[0][x]]+size[son[1][x]]+1;
  }

  inline int rotate(int x)
  {
    int k=t(x),f=fa[x];
    if(fa[f])
      {
        son[t(f)][fa[f]]=x;
      }
    fa[x]=fa[f];
    if(son[!k][x])
      {
        fa[son[!k][x]]=f;
      }
    son[k][f]=son[!k][x];
    fa[f]=x;
    son[!k][x]=f;
    updata(f);
    updata(x);
    return 0;
  }

  inline int splay(int &root,int x,int c)
  {
    while(fa[x]!=c)
      {
        int f=fa[x];
        if(fa[f]==c)
          {
            rotate(x);
          }
        else if(t(x)==t(f))
          {
            rotate(f);
            rotate(x);
          }
        else
          {
            rotate(x);
            rotate(x);
          }
      }
    if(!c)
      {
        root=x;
      }
    return 0;
  }

  inline int getkth(int root,int x)
  {
    int now=root;
    while(now)
      {
        if(size[son[0][now]]+1==x)
          {
            return now;
          }
        else if(size[son[0][now]]+1<x)
          {
            x-=size[son[0][now]]+1;
            now=son[1][now];
          }
        else
          {
            now=son[0][now];
          }
      }
    return 0;
  }

  inline int newnode(int x)
  {
    ++tot;
    val[tot]=x;
    size[tot]=1;
    son[0][tot]=son[1][tot]=0;
    return tot;
  }

  inline int ins(int &root,int x)
  {
    if(!root)
      {
        root=newnode(x);
        fa[tot]=0;
        return 0;
      }
    int now=root;
    while(now)
      {
        int k=val[now]<x;
        if(!son[k][now])
          {
            son[k][now]=newnode(x);
            fa[tot]=now;
            break;
          }
        now=son[k][now];
      }
    splay(root,tot,0);
    return 0;
  }

  inline int del(int &root,int x)
  {
    int now=root;
    while(now)
      {
        if(val[now]==x)
          {
            break;
          }
        else
          {
            now=son[val[now]<x][now];
          }
      }
    splay(root,now,0);
    if((!son[0][now])&&(!son[1][now]))
      {
        root=0;
      }
    else if(!son[0][now])
      {
        root=son[1][now];
        fa[son[1][now]]=0;
      }
    else if(!son[1][now])
      {
        root=son[0][now];
        fa[son[0][now]]=0;
      }
    else
      {
        now=son[0][root];
        while(son[1][now])
          {
            now=son[1][now];
          }
        splay(root,now,root);
        son[1][now]=son[1][root];
        fa[son[1][root]]=now;
        fa[now]=0;
        updata(now);
        root=now;
      }
    return 0;
  }

  int getnext(int now,int x)//找严格大于x的后继
  {
    if(!now)
      {
        return 0;
      }
    else if(val[now]<=x)
      {
        return getnext(son[1][now],x);
      }
    else
      {
        int p=getnext(son[0][now],x);
        if(!p)
          {
            return now;
          }
        else
          {
            return p;
          }
      }
    return 0;
  }

  inline int getrank(int &root,int x)
  {
    int now=getnext(root,x);
    if(!now)
      {
        return size[root];
      }
    splay(root,now,0);
    return size[son[0][now]];
  }
};

struct segment_tree//位置线段树
{
  int root[maxn<<2];
  splay_tree st;

  int build(int now,int left,int right)
  {
    for(register int i=left; i<=right; ++i)
      {
        st.ins(root[now],a[i]);
      }
    if(left==right)
      {
        return 0;
      }
    int mid=(left+right)>>1;
    build(now<<1,left,mid);
    build(now<<1|1,mid+1,right);
    return 0;
  }

  int modify(int now,int left,int right,int pos,int v)
  {
    st.ins(root[now],v);
    st.del(root[now],a[pos]);
    if(left==right)
      {
        return 0;
      }
    int mid=(left+right)>>1;
    if(pos<=mid)
      {
        modify(now<<1,left,mid,pos,v);
      }
    else
      {
        modify(now<<1|1,mid+1,right,pos,v);
      }
    return 0;
  }

  int query(int now,int left,int right,int askl,int askr,int v)
  {
    if((askl<=left)&&(right<=askr))
      {
        int w=st.getrank(root[now],v);
        return w;
      }
    int mid=(left+right)>>1,res=0;
    if(askl<=mid)
      {
        res+=query(now<<1,left,mid,askl,askr,v);
      }
    if(mid<askr)
      {
        res+=query(now<<1|1,mid+1,right,askl,askr,v);
      }
    return res;
  }
};

segment_tree st;
int n,m,aa,b,c;
char s[10];

int main()
{
  scanf("%d%d",&n,&m);
  for(register int i=1; i<=n; ++i)
    {
      scanf("%d",&a[i]);
    }
  st.build(1,1,n);
  while(m--)
    {
      scanf("%s%d%d",s,&aa,&b);
      if(s[0]=='C')
        {
          st.modify(1,1,n,aa,b);
          a[aa]=b;
        }
      else
        {
          scanf("%d",&c);
          int left=0,right=1000000000;
          while(left<=right)
            {
              int mid=(left+right)>>1;
              if(st.query(1,1,n,aa,b,mid)<c)
                {
                  left=mid+1;
                }
              else
                {
                  right=mid-1;
                }
            }
          printf("%d\n",right+1);
        }
    }
  return 0;
}

代码(整体二分版)

#include <cstdio>
#include <algorithm>

const int maxn=10000;
const int maxm=50000;
const int maxs=1000000000;

int n;

struct tree_array
{
  int c[maxn+10];

  inline int lowbit(int x)
  {
    return x&(-x);
  }

  inline int add(int pos,int x)
  {
    while(pos<=n)
      {
        c[pos]+=x;
        pos+=lowbit(pos);
      }
    return 0;
  }

  inline int sum(int pos)
  {
    int res=0;
    while(pos)
      {
        res+=c[pos];
        pos-=lowbit(pos);
      }
    return res;
  }
};

struct data
{
  int l,r,k,id,type;

  inline int make_data(int l_,int r_,int k_,int id_,int type_)
  {
    l=l_;
    r=r_;
    k=k_;
    id=id_;
    type=type_;
    return 0;
  }
};

data d[maxm+10],da[maxm+10],db[maxm+10];
int ans[maxm+10],tot,cnt;
tree_array t;

int solve(int l,int r,int askl,int askr)//整体二分
{
  if(askl>askr)
    {
      return 0;
    }
  if(l==r)
    {
      for(register int i=askl; i<=askr; ++i)
        {
          ans[d[i].id]=l;
        }
      return 0;
    }
  int mid=(l+r)>>1,tl=0,tr=0;
  for(register int i=askl; i<=askr; ++i)
    {
      if(d[i].type==1)
        {
          int tmp=t.sum(d[i].r)-t.sum(d[i].l-1);
          if(tmp>=d[i].k)
            {
              ++tl;
              da[tl]=d[i];
            }
          else
            {
              d[i].k-=tmp;
              ++tr;
              db[tr]=d[i];
            }
        }
      else if(d[i].type==2)
        {
          if(d[i].k<=mid)
            {
              t.add(d[i].l,1);
              ++tl;
              da[tl]=d[i];
            }
          else
            {
              ++tr;
              db[tr]=d[i];
            }
        }
      else
        {
          if(d[i].k<=mid)
            {
              t.add(d[i].l,-1);
              ++tl;
              da[tl]=d[i];
            }
          else
            {
              ++tr;
              db[tr]=d[i];
            }
        }
    }
  for(register int i=askl; i<=askr; ++i)
    {
      if(d[i].type==2)
        {
          if(d[i].k<=mid)
            {
              t.add(d[i].l,-1);
            }
        }
      else if(d[i].type==3)
        {
          if(d[i].k<=mid)
            {
              t.add(d[i].l,1);
            }
        }
    }
  for(register int i=1; i<=tl; ++i)
    {
      d[askl+i-1]=da[i];
    }
  for(register int i=1; i<=tr; ++i)
    {
      d[askl+tl+i-1]=db[i];
    }
  solve(l,mid,askl,askl+tl-1);
  solve(mid+1,r,askl+tl,askr);
  return 0;
}

int num[maxn+10],m,a,b,c;
char opt[10];

int main()
{
  scanf("%d%d",&n,&m);
  for(register int i=1; i<=n; ++i)
    {
      scanf("%d",&num[i]);
      ++tot;
      d[tot].make_data(i,i,num[i],0,2);
    }
  while(m--)
    {
      scanf("%s%d%d",opt,&a,&b);
      if(opt[0]=='Q')
        {
          scanf("%d",&c);
          ++tot;
          ++cnt;
          d[tot].make_data(a,b,c,cnt,1);
        }
      else
        {
          ++tot;
          d[tot].make_data(a,a,num[a],0,3);
          ++tot;
          d[tot].make_data(a,a,b,0,2);
          num[a]=b;
        }
    }
  solve(0,maxs,1,tot);
  for(register int i=1; i<=cnt; ++i)
    {
      printf("%d\n",ans[i]);
    }
  return 0;
}