zoj 2112 动态区间求第k大

题目大意:

动态单点更新,然后多次询问求区间内第k大

这里单个的主席树不能实现,这里采取的是树状数组套主席树

首先可以想的是将静态主席树先构建好,不去动它,这里空间复杂度就是O(nlogn),这个只要之前做过主席树的入门题的话就都不是问题

然后考虑更新的情况,这里将更新产生的前缀变化保存在树状数组中,那么每次更新都要更新logn棵树状数组上的主席树,每一棵的更新操作都是

logn次的,那么时间复杂度就是nlognlogn的只是可以承受的

之后的询问也是,预处理好用到的树状数组,然后保存到向量中,不断处理更新的值

  1 #include <bits/stdc++.h>
  2
  3 using namespace std;
  4 #define N 120010
  5 #define lowbit(x) x&(-x)
  6 #define define_m int m=(l+r)>>1
  7 #define LS(x) node[x].ls
  8 #define RS(x) node[x].rs
  9
 10 vector<int> v1,v2;
 11
 12 struct Node{
 13     int ls , rs , sz;
 14     Node(int ls=0 , int rs=0 , int sz=0):ls(ls),rs(rs),sz(sz){}
 15     void init(){ls=rs=sz=0;}
 16 }node[N*20];
 17 int tot , T1[N] , T2[N] , n , m , val[N]; //T1表示普通节点上的静态主席树,T2表示树状数组上的前缀树
 18 int op[N] , s[N] , t[N] , rank[N];
 19
 20 int Hash(int v){return lower_bound(val , val+n , v)-val+1;}
 21
 22 int build(int l , int r)
 23 {
 24     int u = tot++;
 25     node[u].init();
 26     define_m;
 27     if(l!=r){
 28         LS(u) = build(l , m);
 29         RS(u) = build(m+1 , r);
 30     }
 31     return u;
 32 }
 33
 34 void build(int o1 , int o2 , int l , int r , int pos , int v , int i)
 35 {
 36     if(l==r){
 37         node[o2].sz = node[o1].sz+v;
 38         return;
 39     }
 40     define_m;
 41     node[tot].init();
 42     if(m>=pos){
 43         LS(o2) = tot++ , RS(o2) = RS(o1);
 44         build(LS(o1) , LS(o2) , l , m , pos , v , i);
 45     }else{
 46         LS(o2) = LS(o1) , RS(o2) = tot++;
 47         build(RS(o1) , RS(o2) , m+1 , r , pos , v , i);
 48     }
 49     node[o2].sz = node[LS(o2)].sz+node[RS(o2)].sz;
 50    // cout<<"build : "<<i<<" "<<node[o2].sz<<" "<<l<<" "<<r<<" "<<pos<<endl;
 51 }
 52
 53 void update(int o , int l , int r , int pos , int v)
 54 {
 55    // cout<<pos<<" "<<l<<" "<<r<<" "<<v<<endl;
 56     if(l==r){
 57         node[o].sz += v;
 58         return;
 59     }
 60     define_m;
 61     if(m>=pos) {
 62         if(!LS(o)){
 63             LS(o) = tot++;
 64             node[LS(o)].init();
 65         }
 66         update(LS(o) , l , m , pos , v);
 67     }
 68     else {
 69         if(!RS(o)){
 70             RS(o) = tot++;
 71             node[RS(o)].init();
 72         }
 73         update(RS(o) , m+1 , r , pos , v);
 74     }
 75     node[o].sz = node[LS(o)].sz+node[RS(o)].sz;
 76 }
 77
 78 void add(int x , int pos , int v)
 79 {
 80     while(x<=n){
 81         if(!T2[x]){
 82             node[tot].init();
 83             T2[x] = tot++;
 84         }
 85         update(T2[x] , 1 , n , pos , v);
 86         x += lowbit(x);
 87     }
 88 }
 89
 90 int query(vector<int> v1 , vector<int> v2 , int o1 , int o2 , int l , int r , int k)
 91 {
 92    // cout<<"fuck: "<<l<<" "<<r<<" "<<k<<endl;
 93     if(l==r) return l;
 94     define_m;
 95     int c1 = node[LS(o2)].sz-node[LS(o1)].sz , l1=v1.size() , l2=v2.size();
 96    // cout<<"st: "<<l1<<" "<<l2<<" "<<o1<<" "<<o2<<" "<<node[LS(o2)].sz<<" "<<node[LS(o1)].sz<<" "<<l<<" "<<r<<" "<<k<<endl;
 97     for(int i=0 ; i<l1 ; i++){
 98
 99         c1-=node[LS(v1[i])].sz;
100     }
101     for(int i=0 ; i<l2 ; i++){
102         // if(node[LS(v2[i])].sz) cout<<"i: "<<i<<" "<<node[LS(v2[i])].sz<<endl;
103         c1+=node[LS(v2[i])].sz;
104     }
105   //  cout<<"en: "<<l1<<" "<<l2<<" "<<o1<<" "<<o2<<" "<<c1<<" "<<l<<" "<<r<<" "<<k<<endl;
106     if(c1 >= k){
107         for(int i=0 ; i<l1 ; i++) v1[i] = LS(v1[i]);
108         for(int i=0 ; i<l2 ; i++) v2[i] = LS(v2[i]);
109         return query(v1 , v2 , LS(o1) , LS(o2) , l , m , k);
110     }else{
111         for(int i=0 ; i<l1 ; i++) v1[i] = RS(v1[i]);
112         for(int i=0 ; i<l2 ; i++) v2[i] = RS(v2[i]);
113         return query(v1 , v2 , RS(o1) , RS(o2) , m+1 , r , k-c1);
114     }
115 }
116
117 int query(int s , int t , int k)
118 {
119     v1.clear() , v2.clear();
120     int x = s-1;
121     while(x>0){
122         v1.push_back(T2[x]);
123         x-=lowbit(x);
124     }
125     x = t;
126     while(x>0){
127         v2.push_back(T2[x]);
128         x-=lowbit(x);
129     }
130     return query(v1 , v2 , T1[s-1]  ,T1[t] , 1 , n , k);
131 }
132
133 char str[7];
134 int cur[N];
135
136 int main()
137 {
138     //freopen("in.txt" , "r" , stdin);
139     //freopen("out1.txt" , "w" , stdout);
140     int T;
141     scanf("%d" , &T);
142     while(T--){
143         scanf("%d%d" , &n , &m);
144         tot = 0;
145         for(int i=0 ; i<n ; i++){
146             scanf("%d" , val+i);
147             cur[i+1] = val[i];
148         }
149         int cnt = n;
150         for(int i=0 ; i<m ; i++){
151             scanf("%s%d%d" , str , &s[i] , &t[i]);
152             if(str[0] == ‘Q‘){
153                 scanf("%d" , &rank[i]);
154                 op[i] = 1;
155             }
156             else{
157                 op[i] = 0;
158                 val[cnt++] = t[i];
159             }
160         }
161         sort(val , val+cnt);
162         int pren = n;
163         n = unique(val , val+cnt)-val;
164        // cout<<pren<<" "<<n<<endl;
165         //初始建立静态主席树
166         T1[0] = build(1 , n);
167         for(int i=1 ; i<=pren ; i++){
168             node[tot].init();
169             T1[i] = tot++;
170             build(T1[i-1] , T1[i] , 1 , n , Hash(cur[i]) , 1 , i);
171         }
172
173         memset(T2 , 0 , sizeof(T2));
174         for(int i=0 ; i<m ; i++){
175             if(op[i]){
176                 int pos = query(s[i] , t[i] , rank[i]);
177                 printf("%d\n" , val[pos-1]);
178             }else{
179                 add(s[i] , Hash(cur[s[i]]) , -1);
180                 add(s[i] , Hash(t[i]) , 1);
181                 cur[s[i]] = t[i];
182             }
183         }
184     }
185     return 0;
186 }
时间: 2025-01-02 03:48:20

zoj 2112 动态区间求第k大的相关文章

HDU 2852 KiKi&#39;s K-Number(动态过程求第K小数)

题意: 给出三种操作, 0 在容器中插入一个数. 1 在容器中删除一个数. 2 求出容器中大于a的第k大元素. 思路:可以用树状数组和线段树,显然a[1]+...+a[i]随i有明显的单调性,所以可以二分出答案 线段树时间复杂度比树状数组的常数大了几倍...所以线段树擦边过了 还有另外一种思路:二分只是二分出a[1]+...+a[i]的上界i,所以可以逆向考虑,从a[1]开始累加,直到到达k,这样的复杂度就由原来的 O(lgN*lgN) 变成O(lgN)了.难在累加的过程,线段树和树状数组是同样

hdu 2985 The k-th Largest Group 树状数组求第K大

The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8353   Accepted: 2712 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to g

普林斯顿公开课 算法3-2:求第k大的数

问题 给定N个元素的数组,求第k大的数. 特例 当k=0时,就是求最大值,当k=N-1时,就是求最小值. 应用 顺序统计 求top N排行榜 基本思想 使用快速排序方法中的分区思想,使得a[k]左侧没有更小的数,右侧没有更大的数 性能 快速选择算法的复杂度是N. 最坏情况下的复杂度是1/2N^2,但是可以通过预先洗牌来防止出现最坏情况 代码 public class QuickSort { // 对区间 [start, end) 进行分区 public static int partition(

算法导论学习之线性时间求第k小元素+堆思想求前k大元素

对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思路例如以下: 1.分解:将A[p,r]分解成A[p,q-1]和A[q+1,r]两部分.使得A[p,q-1]都小于A[q],A[q+1,r]都不小于A[q]; 2.求解:假设A[q]恰好是第k小元素直接返回,假设第k小元素落在前半区间就到A[p,q-1]递归查找.否则到A[q+1,r]中递归查找. 3

【大杀器】利用划分树秒杀区间内第k大的数

最近看了一道题,大概就是给出一个序列,不断询问其子区间内第k大的数,下面是个截图 绕了一圈没找到中文版题目,if(你是大佬) then 去看截图:else{我来解释:给出一个整数n,和一个整数m,分别表示序列元素个数和询问次数,然后输入n个数和m个询问,每个询问包含3个数,分别是区间起止点(l和r)和k,求出区间内第k大的数并输出:}这是一道很简单的模板题,怎么解决呢?小编最初想到的是打暴力,正所谓暴力出奇迹,说不定可以成功,反正不会优化,先试试吧,直接把规定区间[l,r]排一次序了,然后在查找

《数据结构与算法分析:C语言描述》读书笔记------练习1.1 求第K大的数

求一组N个数中的第k个最大者,设k=N/2. 1 import java.util.Random; 2 3 4 public class K_Max { 5 6 /** 7 * @param args 8 */ 9 //求第K大的数,保证K大于等于1,小于等于array.length/2哦 10 public static int TopK(int array[],int K) 11 { 12 int topk[] = new int [K]; 13 for(int i = 0; i<topk.

HDU 5249 离线树状数组求第k大+离散化

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1160    Accepted Submission(s): 488 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的

背包问题--求第K大值

这算法有毒,一不小心沾上了不死也脱皮! 在背包问题中这个求第K大值就骚扰了我一整天,让我心神不宁,浑身难受- -! 我看到的这种写法是把原本的DP[X]加一维变成DP[X][Y],X用来确定当前背包容量,Y则是Y个值,分别是记录从最大到第K大,(因为只要求K大,所以那些更小的值就不用记录了) 接下来是讨论这个DP[X][Y],可以理解为它是表示的背包容量为X时的第Y大值,而DP[X][ ]可以理解为所有背包容量为X时的值,这样就方便下面的理解了. 在一般背包解决问题中用的01背包公式大约就是DP

HDU 2639 01背包求第k大

Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3718    Accepted Submission(s): 1903 Problem Description The title of this problem is familiar,isn't it?yeah,if you had took par