【区间k大】HDU 54512 CRB and Queries

通道

题意:区间k大,单点修改

思路:裸,复杂度n(lgn)^2

代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 60010 * 5;
const int M = 100100 * 4;
#define INF 1000000000
char ctrl[M][3];
int cnt,n,m;
int P[M],Q[M],a[N],b[N],K[M];
struct treap{
   int key,wei,cnt,size,ch[2];
}T[N * 15];
int tree[N << 1],nodecnt,root;
void init(){
   T[0].size = 0;
   T[0].wei = -INF;
   nodecnt = root = 0;
}
int ID(int l,int r){return l + r | l != r;}
void update(int x){
   T[x].size = T[T[x].ch[0]].size + T[T[x].ch[1]].size + T[x].cnt;
}
void rotate(int &x,int t){
   int y = T[x].ch[t];
   T[x].ch[t] = T[y].ch[!t];
   T[y].ch[!t] = x;
   update(x);
   update(y);
   x = y;
}
void insert(int &x,int t){
   if (!x){
       x = ++ nodecnt;
       T[x].key = t;
       T[x].wei = rand();
       T[x].cnt = 1;
       T[x].ch[0] = T[x].ch[1] = 0;
   }else if (T[x].key == t) T[x].cnt ++;
   else{
       int k = T[x].key < t;
       insert(T[x].ch[k],t);
       if (T[x].wei < T[T[x].ch[k]].wei) rotate(x,k);
   }
   update(x);
}
void erase(int &x,int t){
   if (T[x].key == t){
       if (T[x].cnt == 1){
           if (!T[x].ch[0] && !T[x].ch[1]) {
               x = 0;return;
           }
           rotate(x,T[T[x].ch[0]].wei < T[T[x].ch[1]].wei);
           erase(x,t);
       }else T[x].cnt --;
   }else erase(T[x].ch[T[x].key < t],t);
   update(x);
}
int select(int x,int t){
   if (!x) return 0;
   if (T[x].key > t) return select(T[x].ch[0],t);
   return T[x].cnt + T[T[x].ch[0]].size + select(T[x].ch[1],t);
}
void treeins(int l,int r,int i,int x){
   insert(tree[ID(l,r)],x);
   if (l == r) return;
   int m = l + r >> 1;
   if (i <= m) treeins(l,m,i,x);
   else treeins(m + 1,r,i,x);
}
void treedel(int l,int r,int i,int x){
   erase(tree[ID(l,r)],x);
   if (l == r) return;
   int m = l + r >> 1;
   if (i <= m) treedel(l,m,i,x);
   else treedel(m + 1,r,i,x);
}
int query(int l,int r,int x,int y,int t){
   if (l == r) return l;
   int m = l + r >> 1;
   int ans = select(tree[ID(l,m)],y) - select(tree[ID(l,m)],x);
   if (ans >= t) return query(l,m,x,y,t);
   return query(m + 1,r,x,y,t - ans);
}
template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c = getchar() , c == EOF) return false;
    while(c != ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar();
    sgn = (c == ‘-‘) ? -1 : 1;
    ret = (c == ‘-‘) ? 0 : (c - ‘0‘);
    while(c = getchar(), c >= ‘0‘ && c <= ‘9‘) ret = ret * 10 + (c - ‘0‘);
    ret *= sgn;
    return true;
}
int main(){
    while (1 == scanf("%d", &n)) {
       memset(tree,0,sizeof tree);
       init();
       cnt = 0;
       for (int i = 1;i <= n;i ++) rd(a[i]),b[++ cnt] = a[i];
       rd(m);
       for (int i = 1;i <= m;i ++){
            scanf("%s", ctrl[i]), rd(P[i]), rd(Q[i]);
           if (ctrl[i][0] == ‘2‘) rd(K[i]);
           else b[++ cnt] = Q[i];
       }
       sort(b + 1,b + 1 + cnt);
       cnt = unique(b + 1,b + 1 + cnt) - b - 1;
       for (int i = 1;i <= n;i ++) {
           a[i] = lower_bound(b + 1,b + 1 + cnt,a[i]) - b;
           treeins(1,cnt,a[i],i);
       }
       for (int i = 1;i <= m;i ++){
           if (ctrl[i][0] == ‘2‘){
               int id = query(1,cnt,P[i] - 1,Q[i],K[i]);
               printf("%d\n",b[id]);
           }else{
               treedel(1,cnt,a[P[i]],P[i]);
               a[P[i]] = lower_bound(b + 1,b + 1 + cnt,Q[i]) - b;
               treeins(1,cnt,a[P[i]],P[i]);
           }
       }
   }
   return 0;
}

时间: 2024-10-24 13:16:28

【区间k大】HDU 54512 CRB and Queries的相关文章

hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)

题目链接:hdu 5412 CRB and Queries 首先对所有出现过的值排序,建立线段树,每个线段树的节点是一棵笛卡尔树,笛卡尔树记录区间下标值. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson(x) (x<<1) #define rson(x) ((x<<

poj2104 划分树 区间K大 在线 无修改

博主sbit....对于高级数据结构深感无力,然后这些东西在OI竟然烂大街了,不搞就整个人都不好了呢. 于是我勇猛的跳进了这个大坑 ——sbit 区间K大的裸题,在线,无修改. 可以用归并树(\(O(nlog^3n)\)),也可用划分树(\(O(nlogn + mlogn)\)).果断划分树...(以后再来看归并树...再来看...来看..看..) 划分树是个什么东西呢?为什么可以做区间k大呢? 想想平衡树做k大时是如何搞的,其实内在原理是一样的. 划分树分两个步骤:建树与询问,这两个步骤相互关

BZOJ 1901: Zju2112 Dynamic Rankings 区间k大 带修改 在线 线段树套平衡树

之前写线段树套splay数组版..写了6.2k..然后弃疗了.现在发现还是很水的..嘎嘎.. zju过不了,超时. upd:才发现zju是多组数据..TLE一版才发现.然后改了,MLE...手写内存池..尼玛终于过了..附zju2112代码于后. bzoj倒是过了,1A的感觉还是很爽的..可是时间不好看..这就是所谓\(O(nlog^3n)\)的复杂度的可怜之处么? 写挂的地方: insert一定要是传地址指针进去. delete时先把地址指针delete掉,最后把是地址指针指向左儿子or右儿子

poj2104 主席树 区间K大 在线 无修改

关于主席树: 主席树(Chairman Tree)是一种离线数据结构,使用函数式线段树维护每一时刻离散之后的数字出现的次数,由于各历史版本的线段树结构一致,可以相减得出区间信息,即该区间内出现的数字和对应的数量,由于在线段树内,左子树代表的数字都小与右子树,便可像平衡树一样进行K大询问.新建一颗树是\(O(logn)\),查询一次也为\(O(logn)\). 比划分树好想&写多了,但是在POJ上比划分树慢一些. CODE: 1 #include <cstdio> 2 #include

HDU 5412 CRB and Queries(区间第K大 树套数 按值建树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5412 Problem Description There are N boys in CodeLand. Boy i has his coding skill Ai. CRB wants to know who has the suitable coding skill. So you should treat the following two types of queries. Query 1:

HDU 5412——CRB and Queries——————【线段树套Treap(并没有AC)】

CRB and Queries Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1602    Accepted Submission(s): 409 Problem Description There are N boys in CodeLand.Boy i has his coding skill Ai.CRB wants to

hdu 5412 CRB and Queries

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5412 CRB and Queries Description There are $N$ boys in CodeLand. Boy i has his coding skill $A_{i}$. CRB wants to know who has the suitable coding skill. So you should treat the following two types of qu

动态求区间K大值(权值线段树)

我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和前一颗树没有关系,so,并不需要可持久化,一个朴素的权值线段树就可以啦. 我们知道普通的线段树是刚开始就把所有的节点都开了,但我们发现并不需要,因为每个点里的操作并不是很多,很大一部分的节点是用不到的,那么我们就可以不开.用Ls 和 Rs 来记左右儿子的地址,随用随开即可. #include<bit

HDU 5412 CRB and Queries (整体二分)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5412 题目大意:对一个数组A[N](N<= 10^5)进行两种操作: 1 l v:将第A[l]的值修改成v 2 l r k:求l~r区间的第k小值 操作总数为10^5. 2015年多校第十场的题目,当时乱套主席树什么的模板,发现并不能过,赛后学习了一种叫做整体二分的方法,感觉很是厉害. 整体二分是二分答案.大致方法如下: 1.先把所有对数组的操作保存起来,包括赋值. 2.从0~inf二分一个数值,并