1901: Zju2112 Dynamic Rankings 【带修改的区间第k小数】

Description

给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

Input

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

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

20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。


带修改的区间第k小数查询

首先我们先不考虑修改操作。那么,写个主席树就好了。

可是现在有修改操作!如果修改了x节点那么x到n的树都需要进行修改。

当然我们可以一棵棵树来修改。可是那样就超时了。

我们这和以前做的树状数组单点修改区间求和类似。所以也许可以用树状数组来维护。

每个树状数组的节点就是一棵主席树,然后修改的时候就和以前做单点修改一样,把对应的树状数组节点的值都改变即可。

如果询问是s t k,那么我们只需要用1到t的减去1到s的然后和没修改操作的一样求区间第k小就可以了。

哦对了因为主席树是离线的。。所以我们需要先把所有出现的数都离散化。


这题是个坑。。嗯。我竟然写了230行。。看着别人100行左右的。我都不好意思贴出来了

以下是代码。。我觉得我写的应该蛮清楚的。。除了离散化那段

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct tree
{
     int l,r;
     int ll,rr;
     int s;
}tr[3000001];
int tot;
int ss;
int pl[100001];
int a[100001];
int n,px;
inline void build(int l,int r)
{
     int p=tot;
     tr[p].l=l;
     tr[p].r=r;
     if(l!=r)
     {
          int mid=(l+r)/2;
          tot++;
          tr[p].ll=tot;
          tot++;
          tr[p].ll=tot;
          build(l,mid);
          tot++;
          tr[p].rr=tot;
          build(mid+1,r);
          tr[p].s=tr[tr[p].ll].s+tr[tr[p].rr].s;
     }
}
inline int inc(int p,int l,int r,int x)
{
	 if(p==0)
	      return 0;
     if(tr[p].l==l&&tr[p].r==r)
     {
          tot++;
          tr[tot].l=l;
          tr[tot].r=r;
          tr[tot].s=tr[p].s+x;
          return tot;
     }
     else
     {
          int mid=(tr[p].l+tr[p].r)/2;
          tot++;
          int pp=tot;
          tr[pp].l=tr[p].l;
          tr[pp].r=tr[p].r;
          if(l<=mid)
               tr[pp].ll=inc(tr[p].ll,l,r,x);
          else
               tr[pp].ll=tr[p].ll;
          if(r>mid)
               tr[pp].rr=inc(tr[p].rr,l,r,x);
          else
               tr[pp].rr=tr[p].rr;
          tr[pp].s=tr[tr[pp].ll].s+tr[tr[pp].rr].s;
          return pp;
     }
}
int N,M;
int L[300],R[300];
inline int ask(int l,int r,int k)
{
     if(l==r)
          return l;
     else
     {
     	  int tmp1=0,tmp2=0;
     	  int i;
     	  for(i=1;i<=N;i++)
     	       tmp1+=tr[tr[L[i]].ll].s;
     	  for(i=1;i<=M;i++)
     	       tmp2+=tr[tr[R[i]].ll].s;
          int tmp=tmp2-tmp1;
          int mid=(l+r)/2;
          if(k<=tmp)
          {
     	       for(i=1;i<=N;i++)
                    L[i]=tr[L[i]].ll;
     	       for(i=1;i<=M;i++)
                    R[i]=tr[R[i]].ll;
               return ask(l,mid,k);
          }
          else
          {
     	       for(i=1;i<=N;i++)
                    L[i]=tr[L[i]].rr;
     	       for(i=1;i<=M;i++)
                    R[i]=tr[R[i]].rr;
               return ask(mid+1,r,k-tmp);
          }
     }
}
inline int lowbit(int x)
{
     return x&(-x);
}
inline void bit_inc(int l,int tt,int x)
{
     int i;
     int tx;
     for(i=l;i<=n;i+=lowbit(i))
     {
     	  tx=pl[i];
          pl[i]=tot+1;
          if(tx==0)
               tx=1;
          inc(tx,tt,tt,x);
     }
}
inline int bit_ask(int l,int r,int k)
{
     int i;
     N=0;
     M=0;
     for(i=l;i>=1;i-=lowbit(i))
     {
     	  N++;
          L[N]=pl[i];
     }
     for(i=r;i>=1;i-=lowbit(i))
     {
          M++;
          R[M]=pl[i];
     }
     return ask(1,px,k);
}

struct number
{
     int t,x;
}b[100001];
int fx[100001];
int pp[100001];
inline bool cmp1(number x,number y)
{
     if(x.x<y.x)
          return true;
     return false;
}
inline bool cmp2(number x,number y)
{
     if(x.t<y.t)
          return true;
     return false;
}
int as[100001][4];
int main()
{
     int m;
     scanf("%d%d",&n,&m);
     int i;
     for(i=1;i<=n;i++)
     {
          scanf("%d",&a[i]);
          b[i].x=a[i];
          b[i].t=i;
     }
     string xx;
     int pxx=n;
     int s,t;
     for(i=1;i<=m;i++)
     {
     	  cin>>xx;
          scanf("%d%d",&s,&t);//区间第x小的数
          if(xx=="C")
          {
               as[i][0]=0;
               as[i][1]=s;
               as[i][2]=t;
               pxx++;
               b[pxx].x=t;
               b[pxx].t=pxx;
          }
          else
          {
               scanf("%d",&as[i][3]);
               as[i][0]=1;
               as[i][1]=s;
               as[i][2]=t;
          }
     }
     sort(b+1,b+1+pxx,cmp1);
     px++;
     fx[px]=b[1].x;
     pp[b[1].t]=px;
     for(i=2;i<=pxx;i++)
     {
          if(b[i].x!=b[i-1].x)
          {
               px++;
               fx[px]=b[i].x;
               pp[b[i].t]=px;
          }
          else
               pp[b[i].t]=px;
     }
     sort(b+1,b+1+pxx,cmp2);
     tot++;
     pl[0]=tot;
     build(1,px);
     for(i=1;i<=n;i++)
          bit_inc(i,pp[i],1);
     int dq=0;
     for(i=1;i<=m;i++)
     {
          if(as[i][0]==0)
          {
               bit_inc(as[i][1],pp[as[i][1]],-1);
               dq++;
               a[as[i][1]]=as[i][2];
               pp[as[i][1]]=pp[b[dq+n].t];
               bit_inc(as[i][1],pp[as[i][1]],1);
          }
          else
               printf("%d\n",fx[bit_ask(as[i][1]-1,as[i][2],as[i][3])]);
     }
     return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值