主席树 刷题记录
一些调试经验
- 要修改某个时间点的树时一定要再整一个新的树出来,不能在上一个树的根节点就这样修改,因为某一个时间点的树永远连着以前的,改了的话会对前面的版本产生影响
- cnt一直在累加,用cnt赋值的时候注意再注意。
洛谷P3834 【模板】可持久化线段树 1(主席树)
- 静态区间第 k 小
- 先把输入的a[i]离散化,假设最后有k个数,再从1~k建树
- 然后从1~n遍历,v[i]表示数i的个数,每个i新建一颗线段树
- 对于询问(l,r),用root[r]的树减去root[l-1]的树即可得到给(l,r)建的线段树
- 在(l,r)建的线段树里查询第k小即可。
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 200010 3 4 using namespace std; 5 int a[nmax], c[nmax], ls[nmax*40], rs[nmax*40], v[nmax*40], root[nmax]; 6 struct px{ 7 int x, id; 8 bool operator < (const px& tmp) const{ 9 return tmp.x > x; 10 } 11 }b[nmax]; 12 int cnt=0; 13 14 int build(int l, int r){ 15 cnt++; 16 int u = cnt; 17 if(l==r) return u; 18 int mid = (l+r)>>1 ; 19 ls[u] = build(l, mid); 20 rs[u] = build(mid+1, r); 21 return u; 22 } 23 24 void upd(int u, int k, int l, int r, int u2){ 25 v[u2] = v[u]+1; 26 if(l==r) return; 27 int mid = (l+r)>>1 ; 28 if(k<=mid) { 29 rs[u2] = rs[u]; 30 ls[u2] = ++cnt; 31 upd(ls[u], k, l, mid, ls[u2]); 32 }else{ 33 ls[u2] = ls[u]; 34 rs[u2] = ++cnt; 35 upd(rs[u], k, mid+1, r, rs[u2]); 36 } 37 } 38 int myfind(int u, int u2, int k, int l, int r){ 39 if(l==r) return l; 40 int num = v[ ls[u2] ] - v[ ls[u] ]; 41 int mid = (l+r)>>1; 42 if(k<=num) return myfind(ls[u], ls[u2], k, l, mid); 43 else return myfind(rs[u], rs[u2], k-num, mid+1, r); 44 } 45 46 int main(){ 47 int n, m; 48 scanf("%d%d", &n, &m); 49 for (int i=1; i<=n; i++) { 50 scanf("%d", &b[i].x); 51 b[i].id = i; 52 } 53 sort(b+1, b+n+1); 54 int idx=1; 55 c[ b[1].id ] = 1; 56 a[1] = b[1].x; 57 for (int i=2; i<=n; i++) { 58 if(b[i].x!=b[i-1].x) idx++; 59 c[ b[i].id ] = idx; 60 a[ idx ] = b[i].x; 61 } 62 build(1, idx); 63 root[0] = 1; 64 for (int i=1; i<=n; i++) { 65 root[i] = ++cnt; 66 upd(root[i-1], c[i], 1, idx, root[i]); 67 } 68 int il, ir, ik; 69 while(m--){ 70 scanf("%d%d%d", &il, &ir, &ik); 71 int t = myfind(root[il-1], root[ir], ik, 1, idx); 72 printf("%d\n", a[t] ); 73 } 74 return 0; 75 }
hduoj5919 Sequence II 2016ccpcchangchunj
- 输入一个数组,有m次询问
- 强制在线,每个询问(l,r),假如(l,r)有k个不同的数,要求输出第(k+1)/2个数的下标
- 倒着从n~1遍历建树,因为每一次要更新两个,一个是i位置要加1,一个是pre[i]要减1
- pre[i]是i位置上的数上一次出现的位置(倒着遍历)
- 这样的话,相当于每次只是某个数第一次出现的地方是1,其他都是0,每个询问直接查询root[l]就行
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 200100 3 4 using namespace std; 5 int n, m, cnt=0; 6 int pos[nmax]={0}, a[nmax], pre[nmax], v[nmax*40], root[nmax], ls[nmax*40], rs[nmax*40]; 7 8 int build(int l, int r){ 9 int u=++cnt; 10 v[u] = 0; 11 if(l==r) return u; 12 int mid = (l+r)>>1; 13 ls[u] = build(l, mid); 14 rs[u] = build(mid+1, r); 15 return u; 16 } 17 18 void upd(int u, int k, int l, int r, int u2, int p){ 19 v[u2] = v[u]+p; 20 if(l==r) return; 21 int mid = (l+r)>>1 ; 22 if(k<=mid) { 23 rs[u2] = rs[u]; 24 ls[u2] = ++cnt; 25 upd(ls[u], k, l, mid, ls[u2], p); 26 }else{ 27 ls[u2] = ls[u]; 28 rs[u2] = ++cnt; 29 upd(rs[u], k, mid+1, r, rs[u2], p); 30 } 31 } 32 33 int getlen(int u, int l, int r, int l1, int r1){ 34 if(l1<=l && r1>=r) return v[u]; 35 int ans = 0; 36 int mid = (l+r)>>1; 37 if(l1 <= mid) ans += getlen(ls[u], l, mid, l1, r1); 38 if(r1 > mid) ans += getlen(rs[u], mid+1, r, l1, r1); 39 return ans; 40 } 41 42 int myfind(int u, int k, int l, int r){ 43 if(l==r) return l; 44 int num = v[ ls[u] ]; 45 int mid = (l+r)>>1; 46 if(k<=num) return myfind(ls[u], k, l, mid); 47 else return myfind(rs[u], k-num, mid+1, r); 48 } 49 50 int main(){ 51 int kas; 52 cin >> kas; 53 for (int cas=1; cas<=kas; cas++) { 54 cnt = 0; 55 scanf("%d%d", &n, &m); 56 for (int i=1; i<=n; i++) { scanf("%d", &a[i]); pos[ a[i] ] = 0; } 57 for (int i=n; i>=1; i--) { 58 pre[i] = pos[ a[i] ]; 59 pos[ a[i] ] = i; 60 } 61 build(1, n); 62 root[n+1] = 1; 63 for (int i=n; i>=1; i--) { 64 root[i] = ++cnt; 65 upd(root[i+1], i, 1, n, root[i], 1); 66 if(pre[i]) { 67 int u = ++cnt; 68 upd(root[i], pre[i], 1, n, u, -1); 69 root[i] = u; 70 } 71 } 72 printf("Case #%d:", cas); 73 int il, ir, li, ri, t = 0, k; 74 while(m--){ 75 scanf("%d%d", &il, &ir); 76 li = min( (il+t)%n+1 , (ir+t)%n+1 ); 77 ri = max( (il+t)%n+1 , (ir+t)%n+1 ); 78 k = getlen(root[li], 1, n, li, ri); 79 t = myfind(root[li], (k+1)/2, 1, n); 80 printf(" %d", t); 81 } 82 printf("\n"); 83 } 84 return 0; 85 }