bzoj3110 K大数查询(整体二分+线段树)

来源:互联网 发布:卡二的网络不好 编辑:程序博客网 时间:2024/05/16 20:30

整体二分

①将修改和查询看做是一条队列。
②二分一个答案Mid,然后扫一下队列,用数据结构来依次(依照操作和询问顺序地)维护修改权值小于或等于Mid的修改对每个查询的贡献。
③将数据结构清空。(注意时间复杂度)
④将修改和询问分成两份,其中
询问:如果问题答案小于或等于Mid,就放在队列1。
如果问题答案大于Mid,修改询问(减掉小于或等于Mid的问题对本答案的贡献),然后放在队列2。
修改:如果修改权值大于或等于Mid,就放在队列1,否则放在队列2。
⑤递归往下做。

程序

#include <iostream>#include <algorithm>#include <string.h>#include <string>#include <cmath>#include <stdio.h>#include <stdlib.h>#include <vector>using namespace std;struct Query{    int q,L,R,v,e;}q[50100],p1[50100],p2[50100];int T[201000],ad[201000],no[50100],ans[50100],n,m;void down(int ro,int L,int R) {    int mid=(L+R)>>1,zuo=ro<<1,you=zuo+1;    T[zuo]+=(mid-L+1)*ad[ro];ad[zuo]+=ad[ro];    T[you]+=(R-mid)*ad[ro];ad[you]+=ad[ro];    ad[ro]=0;}void update(int ro,int L,int R,int le,int ri) {    if (le<=L&&R<=ri) {        T[ro]+=R-L+1; ad[ro]++;        return ;    }    if (L>ri||R<le) return;    if (ad[ro]) down(ro,L,R);    int mid=(L+R)>>1,zuo=ro<<1,you=zuo+1;    update(zuo,L,mid,le,ri);update(you,mid+1,R,le,ri);    T[ro]=T[zuo]+T[you];}int query(int ro,int L,int R,int le,int ri) {    if (le<=L&&R<=ri) return T[ro];    if (L>ri||R<le) return 0;    if (ad[ro]) down(ro,L,R);    int mid=(L+R)>>1,zuo=ro<<1,you=zuo+1;    return query(zuo,L,mid,le,ri)+query(you,mid+1,R,le,ri);}void build(int ro,int L,int R) {    if (T[ro]==0) return;    if (L==R) {T[ro]=ad[ro]=0;return;}    int mid=(L+R)>>1,zuo=ro<<1,you=zuo+1;    build(zuo,L,mid);build(you,mid+1,R);    T[ro]=ad[ro]=0;}void solve(int he,int ta,int L,int R) {    if (ta<he) return;    if (L==R) {        for (int i=he;i<=ta;i++)         if (q[i].q==2)        ans[q[i].e]=L;        return ;    }    int mid=L+R>>1;    for (int i=he;i<=ta;i++) {        if (q[i].q==1&&q[i].v<=mid)            update(1,1,n,q[i].L,q[i].R);        else if (q[i].q==2)            no[i]=query(1,1,n,q[i].L,q[i].R);    }    build(1,1,n);    int cnt1=0,cnt2=0;    for (int i=he;i<=ta;i++)        if (q[i].q==1)             if (q[i].v<=mid) p1[++cnt1]=q[i];            else p2[++cnt2]=q[i];        else if (no[i]>=q[i].v) p1[++cnt1]=q[i];            else {q[i].v-=no[i];p2[++cnt2]=q[i];}    for (int i=1;i<=cnt1;i++) q[i+he-1]=p1[i];    for (int i=1;i<=cnt2;i++) q[he+cnt1+i-1]=p2[i];    solve(he,he+cnt1-1,L,mid);    solve(he+cnt1,ta,mid+1,R);}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=m;i++){        int x,y,z,w;        scanf("%d%d%d%d",&x,&y,&z,&w);        if (x==1)w=-w;        q[i] = (Query) {x,y,z,w,i};    }    for (int i=1;i<=m;i++) ans[i]=-60000;    solve(1,m,-50100,50100);    for (int i=1;i<=m;i++)    if (ans[i]!=-60000) {        if (ans[i]==1) printf("50000\n");        else printf("%d\n",-ans[i]);    }    return 0;}

推荐看

http://www.cnblogs.com/dirge/p/5810855.html

Jeanne d’Arc镇楼

阅读全文
0 0
原创粉丝点击