bzoj1901

1901: Zju2112 Dynamic Rankings

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 6640  Solved: 2762
[Submit][Status][Discuss]

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。

 

Source

 

 题解:区间第k大,加修改操作,就是动态主席树,用主席树套树状数组写,就慢慢地A了。
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<algorithm>
  6 #define maxn 200001
  7 #define maxnode 2200001
  8 using namespace std;
  9 int list[maxn],h[maxn];
 10 int rt[maxnode],lt[maxnode],root[maxnode],sum[maxnode];
 11 int L[maxn],R[maxn];
 12 int ed,st,tot,size,n,node,m;
 13 char ch;
 14 struct date{int l,r,val,k;
 15 }a[maxn];
 16 int read()
 17 {
 18     int x=0; char ch; bool bo=0;
 19     while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') bo=1;
 20     while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9');
 21     if (bo==1) return -x; return x;
 22 }
 23 int lowbit(int k)
 24 {
 25     return (k&(-k));
 26 }
 27 void ins(int x,int &y,int l,int r,int val ,int kk)
 28 {
 29     y=++size;
 30     sum[y]=sum[x]+kk; int mid=(l+r)>>1; rt[y]=rt[x]; lt[y]=lt[x];
 31     if (l==r) return ;
 32     if (val<=mid) ins(lt[x],lt[y],l,mid,val,kk);
 33     else ins(rt[x],rt[y],mid+1,r,val,kk);
 34 }
 35 void build()
 36 {
 37     for (int i=1; i<=n; i++)
 38         for (int j=i; j<=n; j+=lowbit(j)) 
 39         ins(root[j],root[j],1,tot,h[i],1);
 40 }
 41 int query(int l,int r,int k)
 42 {
 43     if (l==r) return l;
 44     int mid=(l+r)>>1; int suml=0,sumr=0;
 45     for (int i=1; i<=st; i++) suml+=sum[lt[L[i]]];
 46     for (int i=1; i<=ed; i++) sumr+=sum[lt[R[i]]];
 47     if (sumr-suml>=k)
 48     {
 49         for (int i=1; i<=st; i++) L[i]=lt[L[i]];
 50         for (int i=1; i<=ed; i++) R[i]=lt[R[i]];
 51         return query(l,mid,k); 
 52     }
 53     else
 54     {
 55         for (int i=1; i<=st; i++) L[i]=rt[L[i]];
 56         for (int i=1; i<=ed; i++) R[i]=rt[R[i]];
 57         return query(mid+1,r,k-sumr+suml);
 58     }
 59 }
 60 void solve()
 61 {
 62     node=n;
 63     for (int i=1; i<=m; i++)
 64     {
 65         if (!a[i].k) 
 66         {
 67             st=ed=0;
 68             a[i].l--;
 69             for (int j=a[i].l; j>0; j-=lowbit(j)) L[++st]=root[j];
 70             for (int j=a[i].r; j>0; j-=lowbit(j)) R[++ed]=root[j];
 71             printf("%d\n",list[query(1,tot,a[i].val)]); 
 72         }
 73         else
 74         {
 75             ++node; 
 76             int t=h[a[i].l];
 77             for (int j=a[i].l; j<=n; j+=lowbit(j)) ins(root[j],root[j],1,tot,t,-1);
 78             h[a[i].l]=t=h[node];
 79             for (int j=a[i].l; j<=n; j+=lowbit(j)) ins(root[j],root[j],1,tot,t,1);
 80             
 81         }
 82     }
 83 }
 84 void clear()
 85 {
 86     tot=size=0;
 87     memset(root,0,sizeof(0));
 88     memset(rt,0,sizeof(0));
 89     memset(lt,0,sizeof(0));
 90     memset(sum,0,sizeof(0));
 91 }
 92 int main()
 93 {
 94     //freopen("dynrank1.in","r",stdin);
 95         clear();
 96         n=read(); m=read();
 97         for (int i=1; i<=n; i++) list[i]=h[i]=read();
 98         tot=n;
 99         for (int i=1; i<=m; i++)
100         {
101             scanf(" %c",&ch);
102             a[i].l=read(); a[i].r=read();
103             if (ch=='Q') a[i].val=read();
104             else a[i].k=1,h[++tot]=list[tot]=a[i].r;
105         } 
106         sort(list+1,list+tot+1);
107         for (int i=1; i<=tot; i++) h[i]=lower_bound(list+1,list+1+tot,h[i])-list;
108         build();
109         solve();
110     return 0;
111 }
View Code

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值