[模板]区间第k大整体二分

https://blog.csdn.net/wu_tongtong/article/details/78825245

https://www.cnblogs.com/sagitta/p/5982251.html

https://blog.csdn.net/wu_tongtong/article/details/78826023

https://blog.csdn.net/wu_tongtong/article/details/79790268

不带修 POJ2104:

#include<iostream>
#include<cstdio>
#include<cstring>
#define lbt(x) (x&-x)
#define INF 2000000000
using namespace std;
const int maxn=100009;
int n,m,tot;
struct qq{
    int x,y,k,id,type;//0 add,1 query
}q[maxn*2],q1[maxn*2],q2[maxn*2];
int ans[maxn*2];
int t[maxn];
void add(int x,int k){
    while(x<=n){
        t[x]+=k;
        x+=lbt(x);
    }
}
int ask(int x){
    int ans=0;
    while(x){
        ans+=t[x];
        x-=lbt(x);
    }
    return ans;
}
void solve(int l,int r,int L,int R){//值域和询问序列 
    if(l>r || L>R)return;
    if(l==r){
        for(int i=L;i<=R;i++)if(q[i].type)ans[q[i].id]=l;
        return;
    }
    int mid=l+r>>1,cnt1=0,cnt2=0;
    for(int i=L;i<=R;i++)
    if(q[i].type){
        int tmp=ask(q[i].y)-ask(q[i].x-1);
        if(tmp>=q[i].k)q1[++cnt1]=q[i];
        else q[i].k-=tmp,q2[++cnt2]=q[i];
    }
    else{
        if(q[i].x<=mid)add(q[i].id,1),q1[++cnt1]=q[i];
        else q2[++cnt2]=q[i];
    }
    for(int i=1;i<=cnt1;i++)if(!q1[i].type)add(q1[i].id,-1);//清空树状数组 
    for(int i=1;i<=cnt1;i++)q[L+i-1]=q1[i];
    for(int i=1;i<=cnt2;i++)q[L+cnt1+i-1]=q2[i];
    solve(l,mid,L,L+cnt1-1);solve(mid+1,r,L+cnt1,R);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,x;i<=n;i++){
        scanf("%d",&x);
        q[++tot].x=x;q[tot].id=i;
    }
    for(int i=1;i<=m;i++){
        tot++;
        scanf("%d%d%d",&q[tot].x,&q[tot].y,&q[tot].k);
        q[tot].type=1;q[tot].id=i;
    }
    solve(-INF,INF,1,tot);
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}

 目前不对:HDU5412

#include<iostream>
#include<cstdio>
#include<cstring>
#define lbt(x) (x&-x)
#define INF 1000000000
using namespace std;
const int maxn=100009;
int n,m,tot,totq,ans[maxn],raw[maxn];
struct node{
    int type,x,y,k,id;//0 add 1 query
}q[maxn*2],q1[maxn*2],q2[maxn*2];
int t[maxn];
void add(int x,int k){
    while(x<=n){
        t[x]+=k;
        x+=lbt(x);
    }
}
int ask(int x){
    int ans=0;
    while(x){
        ans+=t[x];
        x-=lbt(x);
    }
}
void solve(int l,int r,int L,int R){
    if(l>r || L>R)return;
    if(l==r){
        for(int i=L;i<=R;i++)if(q[i].type)ans[q[i].id]=l;
        return;
    }
    int mid=l+r>>1,cnt1=0,cnt2=0;
    for(int i=L;i<=R;i++)
    if(q[i].type){
        int tmp=ask(q[i].y)-ask(q[i].x-1);
        if(tmp>=q[i].k)q1[++cnt1]=q[i];
        else q[i].k-=tmp,q2[++cnt2]=q[i];
    }
    else{
        if(q[i].x<=mid)add(q[i].id,q[i].y),q1[++cnt1]=q[i];
        else q2[++cnt2]=q[i];
    }
    for(int i=1;i<=cnt1;i++)if(!q1[i].type)add(q1[i].id,-q1[i].y);
    for(int i=1;i<=cnt1;i++)q[L+i-1]=q1[i];
    for(int i=1;i<=cnt2;i++)q[L+cnt1+i-1]=q2[i];
    solve(l,mid,L,L+cnt1-1);solve(mid+1,r,L+cnt1,R);
}
int main(){
    while(scanf("%d",&n)!=EOF){
        memset(ans,0,sizeof(ans));
        memset(t,0,sizeof(t));
        tot=0;totq=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&raw[i]);
            q[++tot].x=raw[i];q[tot].y=1;q[tot].id=i;
        }
        scanf("%d",&m);int op;
        for(int i=1,x,y,k;i<=m;i++){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d",&x,&y);
                q[++tot].x=raw[x];q[tot].y=-1;q[tot].id=x;
                raw[x]=y;//用raw数组记录序列状态 
                q[++tot].x=raw[x];q[tot].y=1;q[tot].id=x;
            }
            else{
                scanf("%d%d%d",&x,&y,&k);
                q[++tot].x=x;q[tot].y=y;q[tot].k=k;q[tot].id=++totq;q[tot].type=1;
            }
        }
        solve(1,INF,1,tot);
        for(int i=1;i<=totq;i++)
        printf("%d\n",ans[i]);
    }
}

 

luogu_P1527矩阵乘法:

树状数组换为二维,把每个点塞入一维数组排序,其他没什么大的区别

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lbt(x) (x&-x)
#define INF 1e9
using namespace std;
const int maxn=509;
const int maxm=60009;
int n,m,ans[maxm];
int t[maxn][maxn];
void add(int x,int y,int k){
    for(;x<=n;x+=lbt(x))
    for(int z=y;z<=n;z+=lbt(z))
    t[x][z]+=k;
}
int ask(int x,int y){
    int ans=0;
    for(;x;x-=lbt(x))
    for(int z=y;z;z-=lbt(z))
    ans+=t[x][z];
    return ans;
}
struct node{
    int xa,ya,xb,yb,k,id;
}q[maxm*2],q1[maxm*2],q2[maxm*2];
int tota,tot;
struct aa{
    int x,y,w;
    bool operator <(const aa&xx)const{
        return w<xx.w;
    }
}a[maxn*maxn];
inline int calc(int xa,int ya,int xb,int yb){
    return ask(xb,yb)-ask(xa-1,yb)-ask(xb,ya-1)+ask(xa-1,ya-1);
}
void solve(int l,int r,int L,int R){
    if(L>R || l>r)return;
    if(l==r){
        for(int i=L;i<=R;i++)ans[q[i].id]=a[l].w;
        return;
    }
    int mid=l+r>>1,cnt1=0,cnt2=0;
    for(int i=l;i<=mid;i++)
    add(a[i].x,a[i].y,1);
    for(int i=L;i<=R;i++){
        int tmp=calc(q[i].xa,q[i].ya,q[i].xb,q[i].yb);
        if(tmp>=q[i].k)q1[++cnt1]=q[i];
        else q[i].k-=tmp,q2[++cnt2]=q[i];
    }
    for(int i=l;i<=mid;i++)
    add(a[i].x,a[i].y,-1);
    for(int i=1;i<=cnt1;i++)q[L+i-1]=q1[i];
    for(int i=1;i<=cnt2;i++)q[L+cnt1+i-1]=q2[i];
    solve(l,mid,L,L+cnt1-1);solve(mid+1,r,L+cnt1,R);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,x;i<=n;i++)
    for(int j=1;j<=n;j++){
        scanf("%d",&x);
        a[++tota].x=i;a[tota].y=j;a[tota].w=x;
    }
    sort(a+1,a+tota+1);
    for(int i=1;i<=m;i++){
        tot++;
        scanf("%d%d%d%d%d",&q[tot].xa,&q[tot].ya,&q[tot].xb,&q[tot].yb,&q[tot].k);
        q[tot].id=i;
    }
    solve(1,tota,1,tot);
    for(int i=1;i<=tot;i++)printf("%d\n",ans[i]);
}

 

posted @ 2019-08-02 16:23  羊肉汤泡煎饼  阅读(186)  评论(0编辑  收藏  举报