【BOZJ 1901】Zju2112 Dynamic Rankings

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。

树套树

  1 #include<cstdio>
  2 #include<cstdlib>
  3 using namespace std;
  4 const int N=3000001,inf=1000000000;
  5 struct tree{int lch,rch,num,sz,w,rnd;}tr[N];
  6 int a[10010],n,m,sz,root[10010*4];
  7 void updata(int x){
  8     int l=tr[x].lch,r=tr[x].rch;
  9     tr[x].sz=tr[l].sz+tr[r].sz+tr[x].w;
 10 }
 11
 12 void lturn(int &k)
 13 {int t=tr[k].rch;tr[k].rch=tr[t].lch;tr[t].lch=k;updata(k);updata(t);k=t;}
 14 void rturn(int &k)
 15 {int t=tr[k].lch;tr[k].lch=tr[t].rch;tr[t].rch=k;updata(k);updata(t);k=t;}
 16 void ins(int &k,int x){
 17     if(!k){
 18         k=++sz;tr[k].rnd=rand();tr[k].sz=1;tr[k].num=x;tr[k].w=1;return;
 19     }
 20     if(tr[k].num==x) tr[k].w++;
 21     else if(tr[k].num>x) {
 22         ins(tr[k].lch,x);
 23         if(tr[k].rnd>tr[tr[k].lch].rnd) rturn(k);
 24     }else{
 25         ins(tr[k].rch,x);
 26         if(tr[k].rnd>tr[tr[k].rch].rnd) lturn(k);
 27     }
 28     updata(k);
 29 }
 30
 31 void insert(int k,int l,int r,int x,int y){
 32     if(l<=y&&r>=y) ins(root[k],x);
 33     if(l==r) return;
 34     int mid=(l+r)>>1;
 35     if(y>mid) insert(k<<1|1,mid+1,r,x,y);
 36     else insert(k<<1,l,mid,x,y);
 37 }
 38
 39 int find(int k,int x){
 40     if(!k) return 0;
 41     int l=tr[k].lch,r=tr[k].rch;
 42     if(tr[k].num>x) return find(l,x);
 43     else if(tr[k].num<x) return find(r,x)+tr[l].sz+tr[k].w;
 44     else return tr[l].sz;
 45 }
 46
 47 int get_rank(int k,int l,int r,int L,int R,int x){
 48     int mid=(l+r)>>1;
 49     if(l==L&&r==R) return find(root[k],x);
 50     if(R<=mid) return get_rank(k<<1,l,mid,L,R,x);
 51     else if(L>mid) return get_rank(k<<1|1,mid+1,r,L,R,x);
 52     else return get_rank(k<<1,l,mid,L,mid,x)+get_rank(k<<1|1,mid+1,r,mid+1,R,x);
 53 }
 54
 55 int ask(int x,int y,int rk){
 56     int l=1,r=inf,mid=(l+r)>>1,ans=0;
 57     while(l<=r){
 58         mid=(l+r)>>1;
 59         int k=get_rank(1,1,n,x,y,mid);
 60         if(k<=rk) ans=mid,l=mid+1;
 61         else r=mid-1;
 62     }
 63     return ans;
 64 }
 65
 66 void del(int &k,int p){
 67     if(tr[k].num==p){
 68         if(tr[k].w>1) tr[k].w--,tr[k].sz--;
 69         else{
 70             if(tr[k].lch*tr[k].rch==0) k=tr[k].lch+tr[k].rch;
 71             else if(tr[tr[k].lch].rnd<tr[tr[k].rch].rnd) rturn(k),del(k,p);
 72             else lturn(k),del(k,p);
 73         }
 74     }
 75     else{
 76         tr[k].sz--;
 77         if(tr[k].num>p) del(tr[k].lch,p);else del(tr[k].rch,p);
 78     }
 79 }
 80
 81 void make(int &rt,int p,int t){
 82     ins(rt,t);
 83     del(rt,p);
 84 }
 85
 86 void change(int k,int l,int r,int x,int p,int t){
 87     if(l<=x&&r>=x) make(root[k],p,t);
 88     if(l==r) return;
 89     int mid=(l+r)>>1;
 90     if(x<=mid) change(k<<1,l,mid,x,p,t);
 91     else change(k<<1|1,mid+1,r,x,p,t);
 92 }
 93
 94 int main(){
 95     scanf("%d%d",&n,&m);
 96     for(int i=1;i<=n;i++){
 97         scanf("%d",&a[i]);
 98         insert(1,1,n,a[i],i);
 99     }
100     char s[4];
101     for(int i=1;i<=m;i++){
102         scanf("%s",s);
103         if(s[0]==‘Q‘) {
104             int l,r,rk;
105             scanf("%d%d%d",&l,&r,&rk);
106             printf("%d\n",ask(l,r,rk-1));
107         }else{
108             int x,t;
109             scanf("%d%d",&x,&t);
110             change(1,1,n,x,a[x],t);
111             a[x]=t;
112         }
113     }
114 }

树状数组+主席树

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define N 2200001
 5 using namespace std;
 6 int n,m,tot,top,cnt;
 7 int v[10001],num[20001];
 8 int A[10001],B[10001],X[10001],root[10001],K[10001];
 9 int sz[N],ls[N],rs[N];
10 int L[30],R[30],a,b;
11 int lowbit(int x){return x&(-x);}
12 void updata(int last,int l,int r,int &k,int x,int add){
13     k=++cnt;
14     int mid=(l+r)>>1;
15     sz[k]=sz[last]+add;ls[k]=ls[last];rs[k]=rs[last];
16     if(l==r) return;
17     if(x<=mid) updata(ls[last],l,mid,ls[k],x,add);
18     else updata(rs[last],mid+1,r,rs[k],x,add);
19 }
20
21 int query(int l,int r,int k){
22     if(l==r) return l;
23     int mid=(l+r)>>1;
24     int suml=0,sumr=0;
25     for(int i=1;i<=a;i++)suml+=sz[ls[L[i]]];
26     for(int i=1;i<=b;i++)sumr+=sz[ls[R[i]]];
27     if(sumr-suml>=k){
28         for(int i=1;i<=a;i++) L[i]=ls[L[i]];
29         for(int i=1;i<=b;i++) R[i]=ls[R[i]];
30         return query(l,mid,k);
31     }else{
32         for(int i=1;i<=a;i++) L[i]=rs[L[i]];
33         for(int i=1;i<=b;i++) R[i]=rs[R[i]];
34         return query(mid+1,r,k-(sumr-suml));
35     }
36 }
37
38 int main(){
39     scanf("%d%d",&n,&m);
40     for(int i=1;i<=n;i++){
41         scanf("%d",&v[i]);
42         num[++top]=v[i];
43     }
44     char opt[4];
45     for(int i=1;i<=m;i++){
46         scanf("%s%d%d",opt,&A[i],&B[i]);
47         if(opt[0]==‘Q‘) scanf("%d",&X[i]),K[i]=1;
48         else num[++top]=B[i];
49     }
50     sort(num+1,num+top+1);
51     tot=unique(num+1,num+top+1)-num-1;
52     for(int i=1;i<=n;i++){
53         int t=lower_bound(num+1,num+tot+1,v[i])-num;
54         for(int j=i;j<=n;j+=lowbit(j))
55             updata(root[j],1,tot,root[j],t,1);
56     }
57     for(int i=1;i<=m;i++){
58         if(K[i]){
59             a=0,b=0;A[i]--;
60             for(int j=A[i];j>=1;j-=lowbit(j)) L[++a]=root[j];
61             for(int j=B[i];j>=1;j-=lowbit(j)) R[++b]=root[j];
62             printf("%d\n",num[query(1,tot,X[i])]);
63         }else{
64             int t=lower_bound(num+1,num+tot+1,v[A[i]])-num;
65             for(int j=A[i];j<=n;j+=lowbit(j))
66             updata(root[j],1,tot,root[j],t,-1);
67             v[A[i]]=B[i];
68             t=lower_bound(num+1,num+tot+1,v[A[i]])-num;
69             for(int j=A[i];j<=n;j+=lowbit(j))
70             updata(root[j],1,tot,root[j],t,1);
71         }
72     }
73 }

整体二分

 1 #include<cstdio>
 2 const int inf=1000000000;
 3 struct node{int flag,x,y,no,rk,cur;}p[300100],p1[300100],p2[300010];
 4 int n,m,a[100010],cnt,sum,ans[100100],w[300010],tmp[300010],num;
 5
 6 void add(int x,int y){
 7     for(int i=x;i<=n;i+=(i&(-i))) w[i]+=y;
 8 }
 9
10 int query(int x){
11     int ans=0;
12     for (int i=x;i>0;i-=(i&(-i))) ans+=w[i];
13     return ans;
14 }
15
16 void divid(int h,int t,int l,int r){
17     if(h>t) return;
18     if(l==r) {for(int i=h;i<=t;i++)
19             ans[p[i].no]=l;return;}
20     int mid=(l+r)>>1;
21     for(int i=h;i<=t;i++){
22         if(p[i].flag==1&&p[i].y<=mid) add(p[i].x,1);
23         else if(p[i].flag==2&&p[i].y<=mid) add(p[i].x,-1);
24         else if(p[i].flag==3)tmp[i]=query(p[i].y)-query(p[i].x-1);
25     }
26     for(int i=h;i<=t;i++){
27         if(p[i].flag==1&&p[i].y<=mid) add(p[i].x,-1);
28         else if(p[i].flag==2&&p[i].y<=mid) add(p[i].x,1);
29     }
30     int l1=0,l2=0;
31     for(int i=h;i<=t;i++){
32         if(p[i].flag==3){
33             if(tmp[i]+p[i].cur>p[i].rk-1) p1[++l1]=p[i];
34             else p[i].cur+=tmp[i],p2[++l2]=p[i];
35         }
36         else {
37             if(p[i].y<=mid) p1[++l1]=p[i];else p2[++l2]=p[i];
38         }
39     }
40     for(int i=h;i<=l1+h-1;i++) p[i]=p1[i-h+1];
41     for(int i=l1+h;i<=t;i++) p[i]=p2[i-l1-h+1];
42     divid(h,l1+h-1,l,mid);
43     divid(l1+h,t,mid+1,r);
44 }
45
46 int main(){
47     scanf("%d%d",&n,&m);
48     for(int i=1;i<=n;i++){
49         scanf("%d",&a[i]);
50         p[++cnt].flag=1;p[cnt].x=i;p[cnt].y=a[i];
51     }
52     for(int i=1;i<=m;i++){
53         char opt[4];int x,y,k;
54         scanf("%s%d%d",opt,&x,&y);
55         if(opt[0]==‘Q‘){
56             scanf("%d",&k);
57             p[++cnt].x=x,p[cnt].y=y;p[cnt].flag=3;p[cnt].no=++num;
58             p[cnt].rk=k;
59         }else{
60             p[++cnt].x=x;p[cnt].y=a[x];p[cnt].flag=2;
61             a[x]=y;
62             p[++cnt].x=x;p[cnt].y=a[x];p[cnt].flag=1;
63         }
64     }
65     divid(1,cnt,0,inf);
66     for(int i=1;i<=num;i++) printf("%d\n",ans[i]);
67 } 

这就是时间差距。。。

时间: 2024-10-24 04:53:34

【BOZJ 1901】Zju2112 Dynamic Rankings的相关文章

1901: Zju2112 Dynamic Rankings

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5268  Solved: 2207[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

bzoj 1901: Zju2112 Dynamic Rankings(树套树)

1901: Zju2112 Dynamic Rankings 经典的带修改求区间第k小值问题 树套树模板,我是用的线段树套splay实现的,而且用的数组模拟的,所以可能空间略大,bzoj过了,zoj过不了. 思路很简单,用线段树维护区间,用splay维护区间内的权值,然后询问的时候,二分答案key,然后在区间内找小于key的数有多少个. 贴上模板: #include<stdio.h> #include<string.h> #include<algorithm> #def

BZOJ 1901: Zju2112 Dynamic Rankings 区间k大 带修改 在线 线段树套平衡树

之前写线段树套splay数组版..写了6.2k..然后弃疗了.现在发现还是很水的..嘎嘎.. zju过不了,超时. upd:才发现zju是多组数据..TLE一版才发现.然后改了,MLE...手写内存池..尼玛终于过了..附zju2112代码于后. bzoj倒是过了,1A的感觉还是很爽的..可是时间不好看..这就是所谓\(O(nlog^3n)\)的复杂度的可怜之处么? 写挂的地方: insert一定要是传地址指针进去. delete时先把地址指针delete掉,最后把是地址指针指向左儿子or右儿子

Bzoj 1901: Zju2112 Dynamic Rankings 树套树,线段树,平衡树,Treap

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6471  Solved: 2697[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

BZOJ 1901: Zju2112 Dynamic Rankings( 树状数组套主席树 )

裸的带修改主席树.. 之前用BIT套Splay( http://www.cnblogs.com/JSZX11556/p/4625552.html )A过..但是还是线段树好写...而且快(常数比平衡树小). 时空复杂度是O(Nlog(N)+Mlog^2(N)) ------------------------------------------------------------------------- #include<cstdio> #include<cstring> #in

bzoj 1901: Zju2112 Dynamic Rankings -- 主席树,树状数组,哈希

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB 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继续回答上面的问题. Input 第一行有两个正整数n(1≤

BZOJ1901 Zju2112 Dynamic Rankings 【树状数组套主席树】

题目 给定一个含有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继续回答上面的问题. 输入格式 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000). 分别表示序列的长度和指令的个数. 第二行有n个数,表示a[1],a[2]--a[n],这些数都小于10^9. 接下来的m

【BZOJ 1901】【Zju 2112】 Dynamic Rankings 动态K值 树状数组套主席树模板题

达神题解传送门:http://blog.csdn.net/dad3zz/article/details/50638360 说一下我对这个模板的理解: 看到这个方法很容易不知所措,因为动态K值需要套树状数组,而我一开始根本不知道该怎么套,, 学习吧,,, 然后我自己脑补如果不套会如何?后来想到是查询O(logn),修改是O(nlogn),很明显修改的复杂度太大了,为了降低修改的复杂度,我们只得套上树状数组来维护前缀和使它的n的复杂度降低为logn,从而修改的复杂度变为O(log2n).但因为我们套

【分块】bzoj1901 Zju2112 Dynamic Rankings

区间k大,分块大法好,每个区间内存储一个有序表. 二分答案,统计在区间内小于二分到的答案的值的个数,在每个整块内二分.零散的暴力即可. 还是说∵有二分操作,∴每个块的大小定为sqrt(n*log2(n))比较快呢. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 int n,a[10001],num[