题目大意:
给定一个数列,定义两种操作:
1、修改第n个数的值
2、求[l,r]区间内第k大的值。
方法:
线段树维护区间,treap树维护第k大(splay当然也可以)
树套树第一题。。没想到真的是每个线段树上的节点建一棵平衡树。。。。。
然后修改值就是在所有相关区间内的平衡树里,erase一个值再insert一个值。。。。简直恐怖
查询就是二分答案,因为每个区间都有一棵树,所以可以很快就可以在O(lgn)里算出这个区间内比查询数大的数字有多少个,满足区间加法,最后判断 比判断的这个数大的数是否 <= k,然后可以保证最后一个匹配边界值一定是数列里存在的数。
真是不自己调过一遍的程序没法彻底理解!!!
二分判断是否第k大和求第k大还是有细微差别的。
二分判断要考虑 key[x] == val 的情况 , 而求第k大只需要判断是否找的下去就行
#include <bits/stdc++.h>
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define CLR(arr) memset(arr,0,sizeof(arr))
using namespace std;
int N = 0 , M = 0;
const int maxn = 1020000;
int tmp = 0;
int root[maxn],treapCnt,key[maxn],priority[maxn], //root数组保存每个区间的根节点所对应的平衡数节点的的编号
childs[maxn][2],cnt[maxn],size[maxn];
inline void update(int x){
size[x] = size[ childs[x][0] ] + size[ childs[x][1] ] + cnt[x];
}
inline void rotate(int& x, int t){
int y = childs[x][t];
childs[x][t] = childs[y][!t];
childs[y][!t] = x;
update(x);
update(y);
x = y;
}
void _insert(int& x, int k)
{
if(x){
if(key[x] == k)
cnt[x]++;
else
{
int t = key[x] < k;
_insert(childs[x][t],k);
if(priority[ childs[x][t] ] < priority[x])
rotate(x,t);
}
}
else
{
x = treapCnt++;
key[x] = k;
cnt[x] = 1;
childs[x][0] = childs[x][1] = 0;
priority[x] = rand();
}
update(x);
}
void _erase(int& x, int k)
{
if(key[x] == k)
{
if(cnt[x] > 1)
cnt[x]--;
else
{
if(childs[x][0] == 0 && childs[x][1] == 0)
{
x = 0;
return;
}
int t = priority[ childs[x][0] ] > priority[ childs[x][1] ];
rotate(x,t);
_erase(x,k);
}
} else {
_erase(childs[x][key[x] < k] , k);
}
update(x);
}
void build(int k , int l , int r , int x , int num)
{
_insert(root[k],num); //在每个所经区间的平衡树都加上这个结点
int mid = (l + r) >> 1;
if(l == r) return;
if(x <= mid)
build(lson(k),l,mid,x,num);
else
build(rson(k),mid+1,r,x,num);
}
void change(int k, int l , int r ,int x ,int num,int y){
_erase(root[k],y); //对于所有的经过区间删旧添新
_insert(root[k],num);
if(l == r) return;
int mid = (l + r) >> 1;
if (x <= mid)
change(lson(k),l,mid,x,num,y);
else
change(rson(k),mid+1,r,x,num,y);
}
void finds(int k, int num){
if(!k) return;
if(key[k] <= num)
{
tmp += cnt[k] + size[ childs[k][0] ];
finds( childs[k][1], num);
}
else
finds( childs[k][0], num);
}
void query(int k , int l , int r , int x ,int y, int num)
{
if(l == x && r == y){
finds(root[k],num);
return;
}
int mid = (l + r) >> 1;
if(mid >= y)
query(lson(k),l,mid,x,y,num);
else if (mid < x)
query(rson(k),mid+1,r,x,y,num);
else
{
query(lson(k),l,mid,x,mid,num);
query(rson(k),mid+1,r,mid+1,y,num);
}
}
int a[maxn];
int main(){
size[0] = 0;
priority[0] = INT_MAX;
int T = 0;
scanf("%d",&T);
while(T--){
CLR(root);
treapCnt = 1;
int n = 0 , m = 0;
scanf("%d %d",&n,&m);
for (int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]);
for (int i = 1 ; i <= n ; ++i) build(1,1,n,i,a[i]);
for (int i = 0 ; i < m ; ++i)
{
char s[3];
int x = 0 , y = 0 , z = 0;
scanf("%s",s);
if(s[0] == 'C')
{
scanf("%d %d",&x,&y);
change(1,1,n,x,y,a[x]);
a[x] = y;
}
else
{
scanf("%d %d %d",&x,&y,&z);
int l = 1 , r = 1000000000;
while(l <= r)
{
int mid = (l + r) >> 1;
tmp = 0; query(1,1,n,x,y,mid);
if(tmp >= z) r = mid - 1;
else l = mid + 1;
}
printf("%d\n",l);
}
}
}
return 0;