【分块】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[10001],qx,qy,k,p,v,m,sz,sum,l[101],r[101],b[10001],tmp[1001];
 7 char s[2];
 8 void makeblock()
 9 {
10     memcpy(b,a,sizeof(a));
11     sz=sqrt((double)n*log2(n));
12     for(sum=1;sum*sz<n;sum++)
13       {
14         l[sum]=(sum-1)*sz+1;
15         r[sum]=sum*sz;
16         for(int i=l[sum];i<=r[sum];i++)
17           num[i]=sum;
18         sort(b+l[sum],b+r[sum]+1);
19       }
20     l[sum]=sz*(sum-1)+1;
21     r[sum]=n;
22     sort(b+l[sum],b+r[sum]+1);
23     for(int i=l[sum];i<=r[sum];i++)
24       num[i]=sum;
25 }
26 void query(int L,int R,int k)
27 {
28     if(num[L]+1>=num[R])
29       {
30         int en=0;
31         for(int i=L;i<=R;i++) tmp[++en]=a[i];
32         sort(tmp+1,tmp+en+1);
33         printf("%d\n",tmp[k]);
34       }
35     else
36       {
37         int x=0,y=1000000001;
38         while(x!=y)
39           {
40             int mid=x+y>>1,cnt=0;
41             for(int i=L;i<=r[num[L]];i++) if(a[i]<mid) cnt++;
42             for(int i=l[num[R]];i<=R;i++) if(a[i]<mid) cnt++; //统计<mid的值数
43             for(int i=num[L]+1;i<num[R];i++) cnt+=( lower_bound(b+l[i],b+r[i]+1,mid) - (b+l[i]) );
44             if(cnt>=k) y=mid;
45             else x=mid+1;
46           }
47         printf("%d\n",x-1);
48       }
49 }
50 void update(int p,int v)
51 {
52     *lower_bound(b+l[num[p]],b+r[num[p]]+1,a[p])=v;
53     sort(b+l[num[p]],b+r[num[p]]+1);
54     a[p]=v;
55 }
56 int main()
57 {
58     scanf("%d%d",&n,&m);
59     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
60     makeblock();
61     for(int i=1;i<=m;i++)
62       {
63         scanf("%s",s);
64         if(s[0]==‘Q‘) {scanf("%d%d%d",&qx,&qy,&k);query(qx,qy,k);}
65         else {scanf("%d%d",&p,&v);update(p,v);}
66       }
67     return 0;
68 }
时间: 2024-12-11 12:09:43

【分块】bzoj1901 Zju2112 Dynamic Rankings的相关文章

【分块】【权值分块】bzoj1901 Zju2112 Dynamic Rankings

论某O(n*sqrt(n))的带修改区间k大值算法. 首先对序列分块,分成sqrt(n)块. 然后对权值分块,共维护sqrt(n)个权值分块,对于权值分块T[i],存储了序列分块的前i块的权值情况. 对于区间询问,需要获得区间中每个值出现的次数,然后按权值扫O(sqrt(n)),完整的部分我们可以通过权值分块差分(O(1))得到(比如Lb~Rb块就是T[Rb]-T[Lb-1]),零散的部分我们再维护一个额外的权值分块,累计上该值即可.O(sqrt(n)). 对于修改,直接在该位置之后的所有权值分

【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结点的权值线段树之间毫无关联 可以看这个:http://blog.csdn.net/popoqqq/article/details/40108669?utm_source=tuicool #include<cstdio> #include<algorithm> using namespa

bzoj1901(Zju2112 Dynamic Rankings)

题目链接:没有权限,进不去,题目也没法交,代码也不知道对不对,有好心人有权限帮忙交下吧QAQ 题目大意:带区间修改的第K小数 题目思路:有树套树,块状链表等优秀数据结构可以解决该题,当然我还是继续练习整体二分. 把修改操作拆开成两个操作 1.删除节点上的数 2.加入一个新数,然后更新的时候注意删除操作对树状数组的更新与插入操作相反,其他的没有难度 #include <iostream> #include <cstdio> #include <cstdlib> #incl

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

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】Dynamic Rankings 带修主席树

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