ZOJ 2112 Dynamic Rankings(动态区间第 k 大+块状链表)
题目大意
给定一个数列,编号从 1 到 n,现在有 m 个操作,操作分两类:
1. 修改数列中某个位置的数的值为 val
2. 询问 [L, R] 这个区间中第 k 大的是多少
n<=50,000 m<=10,000
做法分析
本以为某一天我会用 splay 或者 树套树 去搞的,结果被用块状链表搞了
其实这题和链表没什么关系,利用了块状链表分块操作的思想
首先,看看数据规模:n<=50,000,那么,我们每一块的大小可以设置为 sqrt(n) 大概 230 的样子
用一个数组 A 存储整个数列,将数列分块的保存在链表中,每块大小为 230,并且,每一个块都从小到大排序,这样的复杂度是 sqrt(n)*sqrt(n)*log2(sqrt(n))
对于修改操作,先将 A 数组对应的位置的值改了,然后找到对应的分块中,修改并排序,这里可以使用插入排序,也可以直接暴力的调用快排,如果直接调用快排,这里的复杂度是 sqrt(n)*log2(sqrt(n)) 的
对于查询操作:假设查询的是区间 [L, R],先把区间开头和结尾的不在一个整块中的提出去组成一个新块并排序,把在区间中的整块也提出去,这样,当前的询问操作就是在这些块中询问了,这样以后在二分答案,依次在每一个块中寻找不大于当前答案的数是多大,在每一个块中询问的时候,可以使用二分,这样快点
查询的时间复杂度比较难算,大概是:log2(MAX_INTEGER)*sqrt(n)*log2(sqrt(n)) 差不多是 32*225*8 大概 10^4 的样子
那么,总的时间复杂度大概为 M*log2(MAX_INTEGER)*sqrt(n)*log2(sqrt(n)) 为 10^8 级别,题目给了 10 秒,在 zoj 上,这个时间复杂度还是可以去试试的
于是过了,5秒多...
参考代码
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <vector> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int N=50004, LEN=230, INF=0x3fffffff; 10 11 struct Block_List { 12 struct Node { 13 int buff[LEN], Size; 14 void init() { 15 memset(buff, 0, sizeof buff); 16 Size=0; 17 } 18 } List[LEN]; 19 int tot; 20 21 void init(int n, int A[]) { 22 List[0].init(), tot=1; 23 for(int i=0, cur=0; i<n; ) { 24 for(int j=0; i<n && j<LEN; j++, i++) { 25 List[cur].buff[j]=A[i]; 26 List[cur].Size++; 27 } 28 if(i==n) continue; 29 List[tot++].init(); 30 cur++; 31 } 32 for(int i=0; i<tot; i++) sort(List[i].buff, List[i].buff+List[i].Size); 33 } 34 35 void update(int id, int old, int val) { 36 for(int i=0; i<List[id].Size; i++) if(List[id].buff[i]==old) { 37 List[id].buff[i]=val; 38 break; 39 } 40 sort(List[id].buff, List[id].buff+List[id].Size); 41 } 42 43 int query(int id, int val) { 44 int L=0, R=List[id].Size-1; 45 while(L<R) { 46 int mid=(L+R)>>1; 47 if(List[id].buff[mid]>val) R=mid; 48 else L=mid+1; 49 } 50 if(List[id].buff[L]>val) L--; 51 return L+1; 52 } 53 54 void NewNode(int id, int A[], int L, int R) { 55 List[id].init(); 56 for(int i=L; i<=R; i++) List[id].buff[i-L]=A[i]; 57 List[id].Size=R-L+1; 58 sort(List[id].buff, List[id].buff+List[id].Size); 59 } 60 }; 61 62 int A[N], n, m, t; 63 Block_List hehe; 64 char cmd[10]; 65 vector <int> tub; 66 67 int main() { 68 // freopen("in", "r", stdin); 69 scanf("%d", &t); 70 for(int ca=1; ca<=t; ca++) { 71 scanf("%d%d", &n, &m); 72 for(int i=0; i<n; i++) scanf("%d", &A[i]); 73 hehe.init(n, A); 74 for(int i=0, a, b, c; i<m; i++) { 75 scanf("%s", cmd); 76 if(cmd[0]=='Q') { 77 scanf("%d%d%d", &a, &b, &c); 78 a--, b--; 79 int id1=a/LEN, id2=b/LEN; 80 tub.clear(); 81 if(id1==id2) { 82 hehe.NewNode(hehe.tot, A, a, b); 83 tub.push_back(hehe.tot); 84 } 85 else { 86 hehe.NewNode(hehe.tot, A, a, (id1+1)*LEN-1); 87 hehe.NewNode(hehe.tot+1, A, id2*LEN, b); 88 tub.push_back(hehe.tot); 89 tub.push_back(hehe.tot+1); 90 for(int i=id1+1; i<id2; i++) tub.push_back(i); 91 } 92 int L=0, R=INF; 93 while(L<R) { 94 int mid=(L+R)>>1; 95 int sum=0; 96 for(int i=0, len=(int)tub.size(); i<len; i++) { 97 sum+=hehe.query(tub[i], mid); 98 } 99 if(sum<c) L=mid+1; 100 else R=mid; 101 } 102 printf("%d\n", L); 103 } 104 else { 105 scanf("%d%d", &a, &b); 106 a--; 107 hehe.update(a/LEN, A[a], b); 108 A[a]=b; 109 } 110 } 111 } 112 return 0; 113 }
题目链接 & AC 通道