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: 1 l v

The coding skill of Boy l has
changed to v.

Query 2: 2 l r k

This is a report query which asks the k-th
smallest value of coding skill between Boy l and
Boy r(both
inclusive).

Input

There are multiple test cases.

The first line contains a single integer N.

Next line contains N space
separated integers A1, A2,
…, AN,
where Ai denotes
initial coding skill of Boy i.

Next line contains a single integer Q representing
the number of queries.

Next Q lines
contain queries which can be any of the two types.

1 ≤ N, Q ≤ 105

1 ≤ Ai, v ≤ 109

1 ≤ l ≤ r ≤ N

1 ≤ k ≤ r – l +
1

Output

For each query of type 2, output a single integer corresponding to the answer in a single line.

Sample Input

5
1 2 3 4 5
3
2 2 4 2
1 3 6
2 2 4 2

Sample Output

3
4

Author

KUT(DPRK)

Source

2015 Multi-University Training Contest 10

题意:

给出一串数字,然后给出两种操作:

1:1 L V  操作一:把下标为L的点的值替换为 V

2:2 L R K  操作二:在[L, R]区间求第K大!

PS:

这题好像时间卡的比较紧!貌似用树状数组套主席树会T

需要线段树套treap!

代码如下:

//#pragma warning (disable:4786)
//#pragma comment(linker,"/STACK:102400000,102400000")  //手动扩栈
//#include <bits/stdc++.h>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <climits>
#include <ctype.h>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <deque>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-9;
const double PI = acos(-1.00);
//#define PI 3.1415926535897932384626433832795
const double e = exp(1.0);
#define INF 0x3f3f3f3f
//#define INF 1e18
//typedef long long LL;
//typedef __int64 LL;
#define ONLINE_JUDGE
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif

#define N 600010
#define M 100010
struct treap
{
    int key,wht,count,sz,ch[2];
} tp[N*15];
int tree[N<<1];
int nodecount,root;
int IDX(int l,int r)
{
    return l+r | l!=r;
}
void init()
{
    tp[0].sz=0;
    tp[0].wht=-INF;
    nodecount=0;
    root=0;
}
void update(int x)
{
    tp[x].sz=tp[tp[x].ch[0]].sz+tp[x].count+tp[tp[x].ch[1]].sz;
}
void rotate(int &x,int t)
{
    int y=tp[x].ch[t];
    tp[x].ch[t]=tp[y].ch[!t];
    tp[y].ch[!t]=x;
    update(x);
    update(y);
    x=y;
}
void insert(int &x,int t)
{
    if(! x)
    {
        x=++nodecount;
        tp[x].key=t;
        tp[x].wht=rand();
        tp[x].count=1;
        tp[x].ch[0]=tp[x].ch[1]=0;
    }
    else if(tp[x].key==t)  tp[x].count++;
    else
    {
        int k=tp[x].key<t;
        insert(tp[x].ch[k],t);
        if(tp[x].wht<tp[tp[x].ch[k]].wht) rotate(x,k);
    }
    update(x);
}
void erase(int &x,int t)
{
    if(tp[x].key==t)
    {
        if(tp[x].count==1)
        {
            if(! tp[x].ch[0] && ! tp[x].ch[1])
            {
                x=0;
                return;
            }
            rotate(x,tp[tp[x].ch[0]].wht<tp[tp[x].ch[1]].wht);
            erase(x,t);
        }
        else tp[x].count--;
    }
    else erase(tp[x].ch[tp[x].key<t],t);
    update(x);
}
int select(int x,int t)
{
    if(! x) return 0;
    if(tp[x].key>t) return select(tp[x].ch[0],t);
    return tp[x].count+tp[tp[x].ch[0]].sz+select(tp[x].ch[1],t);
}
int a[N],b[N],ord[M][5],lb;
int n,m,tt;
int search(int x)
{
    int l=1,r=b[0],mid;
    while (l<=r)
    {
        mid=(l+r)>>1;
        if(b[mid]==x) return mid;
        if(b[mid]<x) l=mid+1;
        else r=mid-1;
    }
}
void treeinsert(int l,int r,int i,int x)
{
    insert(tree[IDX(l,r)],x);
    if(l==r) return;
    int m=(l+r)>>1;
    if(i<=m) treeinsert(l,m,i,x);
    else treeinsert(m+1,r,i,x);
}
void treedel(int l,int r,int i,int x)
{
    erase(tree[IDX(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 k)
{
    if(l==r) return l;
    int m=(l+r)>>1;
    int ans=select(tree[IDX(l,m)],y)-select(tree[IDX(l,m)],x);
    if(ans>=k) return query(l,m,x,y,k);
    return query(m+1,r,x,y,k-ans);
}
int main ()
{
    while (~scanf("%d",&n))
    {
        b[0]=1;
        lb=0;
        memset(tree,0,sizeof(tree));
        init();
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            b[++lb]=a[i];
        }
        scanf("%d",&m);
        for(int i=1; i<=m; i++)
        {
            int op;
            int x,y,c;
            scanf("%d",&op);
            if(op == 2)
            {
                scanf("%d %d %d",&x,&y,&c);
                ord[i][1]=1;
                ord[i][2]=x;
                ord[i][3]=y;
                ord[i][4]=c;
            }
            else
            {
                scanf("%d %d",&x,&y);
                ord[i][1]=2;
                ord[i][2]=x;
                ord[i][3]=y;
                b[++lb]=y;
            }
        }
        sort(b+1,b+1+lb);
        for(int i=1; i<=lb; i++)
            if(b[i]!=b[b[0]]) b[++b[0]]=b[i];
        for(int i=1; i<=n; i++)
        {
            a[i]=search(a[i]);
            treeinsert(1,b[0],a[i],i);
        }
        for(int i=1; i<=m; i++)
        {
            if(ord[i][1]==1)
                printf("%d\n",b[query(1,b[0],ord[i][2]-1,ord[i][3],ord[i][4])]);
            else
            {
                treedel(1,b[0],a[ord[i][2]],ord[i][2]);
                a[ord[i][2]]=search(ord[i][3]);
                treeinsert(1,b[0],a[ord[i][2]],ord[i][2]);
            }
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-06 20:08:40

HDU 5412 CRB and Queries(区间第K大 树套数 按值建树)的相关文章

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<<

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大 树套树解法

然而过不去你谷的模板 思路: 值域线段树\([l,r]\)代表一棵值域在\([l,r]\)范围内的点构成的一颗平衡树 平衡树的\(BST\)权值为点在序列中的位置 查询区间第\(k\)大值时 左区间在\([l,r]\)范围内的树的大小与\(k\)比较 大了进去,小了减掉换一边 关于建树 递归建估计是\(O(nlog^2n)\)的 Code: #include <cstdio> #include <cstdlib> #include <algorithm> #includ

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 题目大意:对一个数组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二分一个数值,并

hdu 5919 主席树(区间不同数的个数 + 区间第k大)

Sequence II Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 849    Accepted Submission(s): 204 Problem Description Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,?

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

HDU3473--Minimum Sum(静态区间第k大)

Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3047    Accepted Submission(s): 701 Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you

poj2104 求区间第k大 可持久化线段树

poj2104 求区间第k大  可持久化线段树 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef