Hdu-5412 CRB and Queries(整体二分)

来源:互联网 发布:怎么往云镜上下载软件 编辑:程序博客网 时间:2024/05/29 06:47

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 A1A2, …, 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 ≤ NQ ≤ 105 
1 ≤ Aiv ≤ 109 
1 ≤ l ≤ r ≤ N 
1 ≤ k ≤ r C l + 1 

Output

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

Sample Input

51 2 3 4 532 2 4 21 3 62 2 4 2

Sample Output

34题意:带修改的区间第k大。分析:整体二分的做法,对于每一个单独的询问,我们可以很容易设计一个nlogMAXAN的二分答案的算法,但是我们发现如果我们对每一个询问都这样处理的话会有很多重复的操作,于是我们考虑把所有询问一起二分,divide(l,r,x,y)表示l到r的询问所在的答案区间为[x,y],然后我们每次根据mid = (x + y)/2把所有的操作分成两份,左边是插入/删除值小于mid的操作和询问,右边是大于mid的操作和询问,然后递归下去,总复杂度还是n*logMAXANS。
</pre><pre name="code" class="cpp">#include<iostream>#include<string>#include<algorithm>#include<cstdlib>#include<cstdio>#include<set>#include<map>#include<vector>#include<cstring>#include<stack>#include<cmath>#include<queue>#define INF 0x3f3f3f3f#define MAXN 1000000000#define N 100005using namespace std;int n,num,tot,q,a[N],f[N],ans[N],temp[N*3],MAX;struct Ask{    int l,r,v,k,op,p,num;}deal[N*3];int lowbit(int x){    return x & (-x);}void Insert(int k,int x){    while(k <= n)    {        f[k] += x;        k += lowbit(k);    }}int Find(int k){    int cnt = 0;    while(k)    {        cnt += f[k];        k -= lowbit(k);    }    return cnt;}void divide(int l,int r,int x,int y){    if(l > r) return;    if(x == y)    {        for(int i = l;i <= r;i++)         if(deal[i].op == 3) ans[deal[i].num] = x;        return;    }    int mid = (x+y)>>1;    for(int i = l;i <= r;i++)    {        if(deal[i].op == 1 && deal[i].v <= mid) Insert(deal[i].p,1);              //修改        if(deal[i].op == 2 && deal[i].v <= mid) Insert(deal[i].p,-1);        if(deal[i].op == 3) temp[i] = Find(deal[i].r) - Find(deal[i].l-1);    }    for(int i = l;i <= r;i++)    {        if(deal[i].op == 1 && deal[i].v <= mid) Insert(deal[i].p,-1);             //还原        if(deal[i].op == 2 && deal[i].v <= mid) Insert(deal[i].p,1);    }    vector<Ask> t1,t2;    for(int i = l;i <= r;i++)    {        if(deal[i].op == 3)        {            if(temp[i] >= deal[i].k) t1.push_back(deal[i]);            else            {                deal[i].k -= temp[i];                t2.push_back(deal[i]);            }        }        else        {            if(deal[i].v <= mid) t1.push_back(deal[i]);            else t2.push_back(deal[i]);        }    }    int l1 = t1.size(),l2 = t2.size();    for(int i = 0;i < l1;i++) deal[i+l] = t1[i];    for(int i = 0;i < l2;i++) deal[i+l1+l] = t2[i];    divide(l,l+l1-1,x,mid);    divide(l1+l,r,mid+1,y);}int main(){    while(~scanf("%d",&n))    {        MAX = num = tot = 0;        for(int i = 1;i <= n;i++)        {            scanf("%d",&a[i]);            deal[++num].op = 1,deal[num].p = i,deal[num].v = a[i];            MAX = max(MAX,a[i]);        }        scanf("%d",&q);        for(int i = 1;i <= q;i++)        {            int op;            scanf("%d",&op);            if(op == 1)            {                int l,v;                scanf("%d%d",&l,&v);                deal[++num].op = 2,deal[num].p = l,deal[num].v = a[l];                deal[++num].op = 1,deal[num].p = l,deal[num].v = v;                a[l] = v;                MAX = max(MAX,v);            }            else            {                int l,r,k;                scanf("%d%d%d",&l,&r,&k);                deal[++num].op = 3,deal[num].l = l,deal[num].r = r,deal[num].k = k;                deal[num].num = ++tot;            }        }        divide(1,num,1,MAX);        for(int i = 1;i <= tot;i++) printf("%d\n",ans[i]);    }}


0 0
原创粉丝点击