应用场景
静态: 查询区间第K大
动态: 带修改的查询区间第K大
静态
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define clr(a, x) memset(a, x, sizeof(a)) 4 #define rep(i,a,n) for(int i=a;i<=n;i++) 5 #define pre(i,a,n) for(int i=a;i>=n;i--) 6 #define ll long long 7 const double eps = 1e-6; 8 const int INF = 0x3f3f3f3f; 9 const int mod = 1e9 + 7; 10 const int N = 2e5+20; 11 int a[N],b[N],T[N],L[N*20],R[N*20],sum[N*20]; 12 int tot = 0,n,q,x,y,z,m; 13 14 int Build(int l,int r) 15 { 16 int rt = ++tot; 17 int mid = (l+r)>>1; 18 if(l < r) 19 { 20 L[rt] = Build(l,mid); 21 R[rt] = Build(mid+1,r); 22 } 23 return rt; 24 } 25 26 int update(int pre,int l,int r,int x) 27 { 28 int rt = ++tot; 29 int mid = (l+r)>>1; 30 L[rt] = L[pre]; R[rt] = R[pre]; sum[rt] = sum[pre]+1; 31 if(l < r) 32 { 33 if(x <= mid) 34 L[rt] = update(L[pre],l,mid,x); 35 else 36 R[rt] = update(R[pre],mid+1,r,x); 37 } 38 return rt; 39 } 40 41 int query(int u,int v,int l,int r,int k) 42 { 43 if(l == r) 44 return l; 45 int mid = (l+r)>>1; 46 int x = sum[L[v]]-sum[L[u]]; 47 if(x >= k) 48 return query(L[u],L[v],l,mid,k); 49 else 50 return query(R[u],R[v],mid+1,r,k-x); 51 } 52 53 int main() 54 { 55 tot = 0; 56 clr(T,0); clr(sum,0); clr(L,0); clr(R,0); clr(a,0); clr(b,0); 57 scanf("%d %d",&n,&q); 58 rep(i,1,n) 59 { 60 scanf("%d",&a[i]); 61 b[i] = a[i]; 62 } 63 sort(b+1,b+1+n); 64 m = unique(b+1,b+1+n)-b-1; 65 T[0] = Build(1,m); 66 rep(i,1,n) 67 { 68 a[i] = lower_bound(b+1,b+1+m,a[i])-b; 69 T[i] = update(T[i-1],1,m,a[i]); 70 } 71 rep(i,1,q) 72 { 73 scanf("%d %d %d",&x,&y,&z); 74 int p = query(T[x-1],T[y],1,m,z); 75 printf("%d ",b[p]); 76 } 77 return 0; 78 }
动态
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define clr(a, x) memset(a, x, sizeof(a)) 4 #define rep(i,a,n) for(int i=a;i<=n;i++) 5 #define pre(i,a,n) for(int i=n;i>=a;i--) 6 #define ll long long 7 #define lowbit(a) a&(-a) 8 const int N = 200050; 9 10 int cnt,siz,dot,idx; 11 // 内存分配的下标,不同数值点的个数,总共的点数,修改操作的下标 12 int root[N],cpy[N],data[N]; 13 // 静态主席树的根节点,离散化后的数据,原始数据 14 int vir[N],use[N]; 15 // 树状数组的节点,计算前缀和时向前走的节点 16 17 // 因为主席树必须离线,所以将指令存下来 18 struct order 19 { 20 bool typ; // biaoji查询还是修改 21 int from,to,k; 22 }command[N]; 23 24 struct node 25 {int son[2],sum;}tree[N*250]; 26 // 内存一定要开的足够大,因为在这里静态主席树和树状数组共用这个数组内的点 27 28 int build(int l,int r) // 建立空树 类似线段树 29 { 30 int now = cnt++; 31 tree[cnt].sum = 0; 32 if(l != r) 33 { 34 int mid = (l+r)>>1; 35 tree[now].son[0] = build(l,mid); 36 tree[now].son[1] = build(mid+1,r); 37 } 38 return now; 39 } 40 41 int updata(int last,int pos,int val) // 更新虚拟节点或者插入静态主席树的函数 42 // 为了方便删除,传入val代表修改的量 43 { 44 int now = cnt++,tmp = now,mid; 45 int l = 0,r = siz-1; // 保存的是离散化后的对应的值的编号 46 tree[now].sum = tree[last].sum+val; 47 while(l < r) 48 { 49 mid = (l+r)>>1; 50 if(pos <= mid) // 待插入节点在左子树 51 { 52 tree[now].son[1] = tree[last].son[1]; 53 // 那么当前节点的右子树节点和之前的那棵权值线段树共用节点 54 tree[now].son[0] = cnt++; // 向左新开一个节点 55 now = tree[now].son[0]; 56 last = tree[last].son[0]; 57 r = mid; 58 } 59 else // 待插入节点在右子树 60 { 61 tree[now].son[0] = tree[last].son[0]; 62 tree[now].son[1] = cnt++; 63 now = tree[now].son[1]; 64 last = tree[last].son[1]; 65 l = mid+1; 66 } 67 tree[now].sum = tree[last].sum+val; 68 } 69 return tmp; 70 } 71 72 void add(int now,int pos,int val) 73 { 74 while(now <= dot) 75 { 76 vir[now] = updata(vir[now],pos,val); 77 now += lowbit(now); 78 } 79 } 80 81 int getsum(int now) // 查询当前点更改值的左子树的大小 82 { 83 int ret = 0; 84 while(now > 0) 85 { 86 ret += tree[tree[use[now]].son[0]].sum; 87 now -= lowbit(now); 88 } 89 return ret; 90 } 91 92 int query(int l,int r,int kth) 93 { 94 int left_root = root[l-1]; // 静态主席树的两个相减的根节点 95 int right_root = root[r]; 96 int lef = 0,rig = siz-1; // 查询时左右范围 97 for(int i = l-1;i;i -= lowbit(i)) use[i] = vir[i]; 98 // 初始化更改值的路径 99 for(int i = r;i;i -= lowbit(i)) use[i] = vir[i]; 100 while(lef < rig) 101 { 102 int mid = (lef+rig)>>1; 103 int now_sum = getsum(r)-getsum(l-1)+tree[tree[right_root].son[0]].sum-tree[tree[left_root].son[0]].sum; 104 // 查询当前点的左儿子是否满足达到了k个 105 // 在静态主席树和树状数组上一起算 106 if(now_sum >= kth) // 达到了 107 { 108 rig = mid; 109 for(int i = l-1;i;i -= lowbit(i)) use[i] = tree[use[i]].son[0]; 110 // 将查询范围缩小至左子树内 111 for(int i = r;i;i -= lowbit(i)) use[i] = tree[use[i]].son[0]; 112 left_root = tree[left_root].son[0]; // 同时静态主席树也要如此 113 right_root = tree[right_root].son[0]; 114 } 115 else // 没达到就在右子树范围内继续查找 116 { 117 lef = mid+1; 118 kth -= now_sum; // 因为有了左子树的一部分点,所以要减去 119 for(int i = l-1;i;i -= lowbit(i)) use[i] = tree[use[i]].son[1]; 120 for(int i = r;i;i -= lowbit(i)) use[i] = tree[use[i]].son[1]; 121 left_root = tree[left_root].son[1]; 122 right_root = tree[right_root].son[1]; 123 } 124 } 125 return lef; // 返回是第几个离散出来的数据 126 } 127 128 int id(int now) 129 { 130 return lower_bound(cpy,cpy+siz,now)-cpy; 131 } 132 133 int main() 134 { 135 int num; 136 scanf("%d %d",&dot,&num); 137 idx = dot; 138 for(int i = 1;i <= dot;i++) 139 { 140 scanf("%d",&data[i]); 141 cpy[i-1] = data[i]; // cpy从0开始存方便unique和sort 142 } 143 char c[10]; 144 for(int i = 1;i <= num;i++) 145 { 146 scanf("%s",c); 147 if(c[0] == 'Q') 148 { 149 command[i].typ = false; 150 scanf("%d %d %d",&command[i].from,&command[i].to,&command[i].k); 151 } 152 else 153 { 154 command[i].typ = true; 155 scanf("%d %d",&command[i].from,&command[i].k); 156 cpy[idx++] = command[i].k; // 如果是修改的话存入cpy中 157 } 158 } 159 sort(cpy,cpy+idx); 160 siz = unique(cpy,cpy+idx)-cpy; 161 root[0] = build(0,siz-1); // 建立空静态主席树 162 for(int i = 1;i <= dot;i++) 163 root[i] = updata(root[i-1],id(data[i]),1); // 建立满的静态主席树 164 for(int i = 1;i <= dot;++i) 165 vir[i] = root[0]; // 初始化树状数组 166 for(int i = 1;i <= num;i++) // 处理指令 167 { 168 if(!command[i].typ) 169 printf("%d ",cpy[query(command[i].from,command[i].to,command[i].k)]); 170 else 171 { 172 add(command[i].from,id(data[command[i].from]),-1); 173 add(command[i].from,id(command[i].k),1); 174 data[command[i].from] = command[i].k; // 将原数据修改至新数据 175 } 176 } 177 return 0; 178 }