Hdu CRB and Queries(整体二分)

CRB and Queries
Time Limit: 6000 MS Memory Limit: 131072 K
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小.
把操作离线.
修改操作视为一个删除操作和一个添加操作.
然后和静态处理方式相同. 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 400001
#define INF 1e9
using namespace std;
struct data{int x,y,k,s,o,cut;}
q[MAXN],tmp1[MAXN],tmp2[MAXN];
int n,m,tot,cut,s[MAXN],ans[MAXN],a[MAXN],tmp[MAXN];
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
    return x*f;
}
void add(int x,int z)
{
    while(x<=n) s[x]+=z,x+=x&-x;
    return ;
}
int getsum(int x)
{
    int sum=0;
    while(x>0) sum+=s[x],x-=x&-x;
    return sum;
}
void slove(int head,int tail,int l,int r)
{
    if(head>tail) return ;
    if(l==r)
    {
        for(int i=head;i<=tail;i++)
          if(q[i].o==3) ans[q[i].s]=l;
        return ;
    }
    int mid=(l+r)>>1;
    for(int i=head;i<=tail;i++)//统计贡献.
    {
        if(q[i].o==1&&q[i].y<=mid) add(q[i].x,1);
        else if(q[i].o==2&&q[i].y<=mid) add(q[i].x,-1);
        else if(q[i].o==3) tmp[i]=getsum(q[i].y)-getsum(q[i].x-1);
    }
    for(int i=head;i<=tail;i++)
    {
        if(q[i].y<=mid)
        {
            if(q[i].o==1) add(q[i].x,-1);
            else if(q[i].o==2) add(q[i].x,1);
        }
    }
    int l1=0,l2=0;
    for(int i=head;i<=tail;i++)
    {
        if(q[i].o==3)
        {
            if(q[i].cut+tmp[i]>q[i].k-1) tmp1[++l1]=q[i];
            //对于该操作找一个所属答案位置.
            else q[i].cut+=tmp[i],tmp2[++l2]=q[i];
        }
        else
        {
            if(q[i].y<=mid) tmp1[++l1]=q[i];
            else tmp2[++l2]=q[i];
        }
    }
    for(int i=1;i<=l1;i++) q[head+i-1]=tmp1[i];
    for(int i=1;i<=l2;i++) q[head+l1+i-1]=tmp2[i];
    slove(head,head+l1-1,l,mid),slove(head+l1,tail,mid+1,r);
    return ;
}
void Clear()
{
    memset(q,0,sizeof q);
    //memset(s,0,sizeof s);
    //memset(ans,0,sizeof ans);
    tot=cut=0;return ;
}
int main()
{

    int x,y,z,k;
    while(scanf("%d",&n)!=EOF)
    {
        Clear();
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            q[++tot].x=i,q[tot].y=a[i];
            q[tot].o=1,q[tot].s=0;
        }
        m=read();
        while(m--)
        {
            z=read();
            if(z==2)
            {
                x=read(),y=read(),k=read();
                q[++tot].x=x,q[tot].y=y,q[tot].k=k;
                q[tot].o=3;q[tot].s=++cut;
            }
            else
            {
                x=read(),y=read();
                q[++tot].x=x,q[tot].y=a[x];
                q[tot].o=2,q[tot].s=0;
                q[++tot].x=x,q[tot].y=y;
                q[tot].o=1,q[tot].s=0;
                a[x]=y;
            }
        }
        slove(1,tot,-INF,INF);
        for(int i=1;i<=cut;i++) printf("%d\n",ans[i]);
    }
    return 0;
}
posted @ 2017-02-22 14:33  nancheng58  阅读(220)  评论(0编辑  收藏  举报