[ZJOI2013]K大数查询

整体二分?

二分答案c,求:

solve(optl,optr,ansl,ansr);

即work出操作在[ol,or],答案在[al,ar]?

先搞出一个答案mid,再把opt扫一边。

如果是1

如果c>mid,就丢进树状数组里面。

区间+1?

三个树状数组的事情。

然后把操作扔进右边QwQ

如果c<=mid 就不管它

然后把操作丢进左边。

如果是2

查询一下和。

如果sum<k

则意味着前面的操作里凑不出k个比mid大的数。

则第k大一定比mid小。

丢进左边。

否则 丢进右边。

然后

solve(optl,sizel,ansl,mid);

solve(sizel+1,optr,mid+1,ansr);

直到l==r为止。

上代码:

//MADE BY BOBOYANG
#include <bits/stdc++.h>
#define LL long long int
#define dob double
using namespace std;
const int N = 50010;
struct Data{
  int type,l,r,c,id;
  bool operator <(const Data &a)const{
    return id<a.id;
  }
}opt[N],que1[N],que2[N];
int n,m,tim;LL Ans[N];
struct BIT{
  LL A1[N],A2[N],A3[N];
  int vis1[N],vis2[N],vis3[N];
  inline int lb(int k){
    return k&-k;
  }
  inline void update(LL *A,int *vis,int x,int val){
    for(;x<=n;x+=lb(x)){
      if(vis[x]!=tim)A[x]=0;
      A[x]+=val;vis[x]=tim;
    }
  }
  inline LL query(LL *A,int *vis,int x,LL ans=0){
    for(;x;x-=lb(x)){
      if(vis[x]!=tim)A[x]=0;
      ans+=A[x];vis[x]=tim;
    }
    return ans;
  }
  inline void add(int l,int r,int dt){
    update(A2,vis2,l,dt);update(A2,vis2,r+1,-dt);
    update(A3,vis3,l,dt*l);update(A3,vis3,r+1,-dt*(r+1));
  }
  inline LL sum(int l,int r){
    LL sl=A1[l-1]+l*query(A2,vis2,l-1)-query(A3,vis3,l-1);
    LL sr=A1[r]+(r+1)*query(A2,vis2,r)-query(A3,vis3,r);
    return sr-sl;
  }
}T;
inline int gi(){
  int x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}
inline void solve(int optl,int optr,int l,int r){
  if(optl>optr)return;++tim;
  if(l==r){
    for(int i=optl;i<=optr;++i)
      if(opt[i].type==2)
        Ans[opt[i].id]=l;
    return;
  }
  int mid=((l+r+2*n)>>1)-n,tot1=0,tot2=0;
  for(int i=optl;i<=optr;++i){
    if(opt[i].type==1){
      if(opt[i].c>mid){
        T.add(opt[i].l,opt[i].r,1);
        que2[++tot2]=opt[i];
      }
      else que1[++tot1]=opt[i];
    }
    else{
      LL sum=T.sum(opt[i].l,opt[i].r);
      if(sum<opt[i].c){
        opt[i].c-=sum;
        que1[++tot1]=opt[i];
      }
      else que2[++tot2]=opt[i];
    }
  }
  int k=optl;
  for(int i=1;i<=tot1;++i)opt[k++]=que1[i];
  for(int i=1;i<=tot2;++i)opt[k++]=que2[i];
  solve(optl,optl+tot1-1,l,mid);
  solve(optr-tot2+1,optr,mid+1,r);
}
int main()
{
  n=gi();m=gi();
  for(int i=1;i<=m;++i){
    opt[i].type=gi();
    opt[i].l=gi();opt[i].r=gi();
    opt[i].c=gi();opt[i].id=i;
  }
  solve(1,m,-n,n);
  sort(opt+1,opt+m+1);
  for(int i=1;i<=m;++i)
    if(opt[i].type==2)
      printf("%lld\n",Ans[i]);
  return 0;
}
posted @ 2019-08-31 07:37  颓废の子乃酱  阅读(140)  评论(0编辑  收藏  举报