您的位置:首页 > 产品设计 > UI/UE

hdu 5412 CRB and Queries 2015多校联合训练赛#10 分治 求区间第k大数

2015-08-22 11:39 721 查看


CRB and Queries

Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 636 Accepted Submission(s): 162



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

求区间第k大数,http://www.cnblogs.com/zig-zag/archive/2013/04/18/3027707.html 参考这篇博客,然后看2013年集训队XHR论文。吧

解法:操作分三种,

1. 加入一个数,

2. 删除一个数,

3. 询问答案在左区间还是又区间

方法:

二分询问的答案是什么。

对于初始数字,变为插入操作

按操作的时间顺序排列各个操作,对于修改操作拆为删除和加入操作

:1 删除之前插入的数字,2. 加入新的数字

接下来分治二分答案:

对于mid,如果插入或者删除的数字<=mid那么应该放到左区间,并且用树状数组(其他数据结构也行)

维护前X个位置有多少个数字在左边。

对于询问:如果l,r区间在左边的数字>=k那么答案在左边,否则答案在右边,并且更新K,k=k-这个区间去左边的数字个数

当low =high的时候,说明low就是答案了,只要更新询问还在low,low之间的答案即可。

复杂度分析:分治的深度是log(S)s是数据的范围。

每个询问每次被分到左边或者右边,会有log(s)次操作。每个插入或者删除也是。

但是要用树状数组维护多少个数字在左边,要log(n)次更新或者查询。

复杂度是n*log(s)*log(n)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
#define maxn 300007
int tree[maxn];
void add(int p,int n){
    for(;p<maxn;p+=p&(-p))
        tree[p]+=n;
}
int query(int p){
    int ans = 0;
    for(;p>0;p-=p&(-p))
        ans += tree[p];
    return ans;
}

struct Node{
    int l,r,k,ty,ans;
};
Node p[maxn];
int id1[maxn],id2[maxn];
void CDQ(int L,int R,int low,int high){
    if(R < L) return ;
    if(low == high ){
        for(;L<=R;L++){
            p[id1[L]].ans = low;
        }
        return ;
    }
    int mid = (low+high)/2,l=L,r=R,k,u;
    for(int i = L;i <= R; i++){
        u = id1[i];
       if(p[u].ty == 2){
            k = query(p[u].r) - query(p[u].l-1);
            if(k >= p[u].k) id2[l++] = u;
            else {
                p[u].k -= k;
                id2[r--] = u;
            }
        }
        else if(p[u].k <= mid){
            add(p[u].l,p[u].ty);
            id2[l++] = u;
        }
        else id2[r--] =  u;
    }

    for(int i = L; i <= R; i++){
        u = id1[i];
        if(p[u].ty != 2 && p[u].k <= mid) add(p[u].l,-p[u].ty);
    }
    for(k=L;k<l;k++)
        id1[k] = id2[k];
    for(r=R;k<=R;k++)
        id1[k] = id2[r--];
    CDQ(L,l-1,low,mid);
    CDQ(l,R,mid+1,high);
}

int num[maxn];

int main(){
    int n,q,t,cnt;
    memset(tree,0,sizeof(tree));
    while(scanf("%d",&n)!=EOF){
        for(cnt=0;cnt<n;cnt++){
            scanf("%d",&p[cnt].k);
            p[cnt].ty = 1;
            p[cnt].l = cnt+1;
            num[cnt+1] = p[cnt].k;
        }
        scanf("%d",&q);
        int ty,l,v;
        for(int i = 0;i < q; i++,cnt++){
            scanf("%d",&p[cnt].ty);
            if(p[cnt].ty == 1){
                scanf("%d%d",&l,&v);
                p[cnt].ty = -1;
                p[cnt].k = num[l];
                p[cnt].l = l;
                cnt++;
                num[l] = v;
                p[cnt].ty = 1;
                p[cnt].k = v;
                p[cnt].l = l;
            }
            else {
                scanf("%d%d%d",&p[cnt].l,&p[cnt].r,&p[cnt].k);
            }
        }
        for(int i = 0;i < cnt; i++)
            id1[i] = i;
        CDQ(0,cnt-1,0,1000000000);
        for(int i = 0;i < cnt; i++){
            if(p[i].ty == 2) printf("%d\n",p[i].ans);
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: