疯狂求导 - BIT - 主席树

题目大意就是区间push_back一个数字,求区间不严格第K大之类的,强制在线。然后你直接像区间加区间求和的BIT那样差分后维护自己和自己乘以下标即可, O ( m lg ⁡ 2 n ) O(m\lg^2n) O(mlg2n)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define lint long long
#define gc getchar()
#define lb(x) ((x)&(-(x)))
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define N 200010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
const int mxa=1000010;int n,m;
inline int inn() { int x,ch; while((ch=gc)<'0'||ch>'9');x=ch^'0';while((ch=gc)>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^'0');return x; }
inline lint inln(){lint x,ch;while((ch=gc)<'0'||ch>'9');x=ch^'0';while((ch=gc)>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^'0');return x; }
struct segment{
    lint s;segment *ch[2];
}*A[N],*B[N],*tmp,*ansT[N],*savT[N];
int sgn[N],ansc;lint sa[N],sb[N];
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->s=0;if(l==r) return 0;int mid=(l+r)>>1;
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),0;
}
int update(segment* &y,segment* &x,int p,lint v,int l=1,int r=mxa)
{
    x=new segment,x->s=y->s+v,x->ch[0]=y->ch[0],x->ch[1]=y->ch[1];
    if(l==r) return 0;int mid=(l+r)>>1;
    if(p<=mid) update(y->ch[0],x->ch[0],p,v,l,mid);
    else update(y->ch[1],x->ch[1],p,v,mid+1,r);return 0;
}
lint query(segment* &rt,int s,int t,int l=1,int r=mxa)
{
    if(s<=l&&r<=t) return rt->s;lint ans=0;int mid=(l+r)>>1;
    if(s<=mid) ans+=query(rt->ch[0],s,t,l,mid);
    if(mid<t) ans+=query(rt->ch[1],s,t,mid+1,r);return ans;
}
inline segment* upd(segment* &rt,int p,lint v) { return update(rt,tmp,p+1,v),tmp; }
inline int upd(int x,int p,int v)
{
    if(x<=0||x>n) return 0;int va=v,vb=v*x;
    for(;x<=n;x+=lb(x)) A[x]=upd(A[x],p,va),B[x]=upd(B[x],p,vb);
    return 0;
}
inline int _query(int x,int va,int vb)
{
    if(x<=0||x>n) return 0;
    for(;x;x-=lb(x)) ansT[++ansc]=A[x],sgn[ansc]=va,(vb?ansT[++ansc]=B[x],sgn[ansc]=vb:0);
    return 0;
}
inline int qry(int s,int t,int v) { return _query(t,v,-1),_query(s-1,-v,1),_query(s-1,t-s+1,0); }
int main()
{
    n=inn(),m=inn(),build(A[0],1,mxa),B[0]=A[0];rep(i,1,n) inn(),A[i]=A[0],B[i]=B[0];
//  int x;rep(i,1,n) x=(inn()>0),sa[i]=sa[i-1]+x,sb[i]=sb[i-1]+x*i;
//  rep(i,1,n) A[i]=upd(A[0],0,sa[i]-sa[i-lb(i)]),B[i]=upd(B[0],0,sb[i]-sb[i-lb(i)]);//,debug(i)sp,debug(A[i]->s)sp,debug(B[i]->s)ln;
    for(int lasp=0;m;m--)
    {
        int opt=inn(),l=inn(),r=inn(),a;lint s;
        if(!opt) a=inn()^lasp,(a?upd(l,a,1),upd(r+1,a,-1):0);
        else{
            s=inln(),ansc=0,qry(l,r,r+1),l=1,r=mxa;
            lint ts=0;rep(i,1,ansc) ts+=sgn[i]*ansT[i]->s;
            if(ts<=s) { printf("%d %lld\n",lasp=1,ts);continue; }
            s++;rep(i,1,ansc) savT[i]=ansT[i];lint anss=0;
            while(l<r)
            {
                int mid=(l+r)>>1;ts=0;
                rep(i,1,ansc) ts+=sgn[i]*ansT[i]->ch[1]->s;
                if(s>ts) { s-=ts;rep(i,1,ansc) ansT[i]=ansT[i]->ch[0];r=mid,anss+=ts; }
                else { rep(i,1,ansc) ansT[i]=ansT[i]->ch[1];l=mid+1; }
            }
            printf("%d %lld\n",lasp=l,anss);
        }
//      rep(i,1,n) debug(i)sp,debug(A[i]->s)sp,debug(B[i]->s)ln;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值