JZOJ5419. 【NOIP2017提高A组集训10.24】线段树

很烦人的线段树= =。不过理解了以后还是挺好打的,就是太长。
具体的话就是维护每一个区间内到左端点右端点的最小代价和最左边,最右边的可用的位置,然后直接更新就好了,至于查询的话,就是查询中位数咯,查询一下中位数左右两边最靠近他的可用的点,然后取个代价最小的。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=2e5+5;
typedef long long ll;
const ll inf=1e17;
int n,m,a[N];
struct tree
{
    int lb,rb,lazy,sb;
    ll tol,tor,s;
}t[N*5];
struct node
{
    int x;
    ll y;
};
int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void pushup(int x,int l,int r)
{
    int mid=(l+r)>>1;
    t[x].lb=t[x<<1].lb?t[x<<1].lb:t[x<<1|1].lb;
    t[x].rb=t[x<<1|1].rb?t[x<<1|1].rb:t[x<<1].rb;
    t[x].sb=t[x<<1].sb+t[x<<1|1].sb;
    t[x].s=t[x<<1].s+t[x<<1|1].s;
    t[x].tol=t[x<<1].tol+t[x<<1|1].tol+1ll*t[x<<1|1].s*(mid-l+1);
    t[x].tor=t[x<<1|1].tor+t[x<<1].tor+1ll*t[x<<1].s*(r-mid);
}
inline void pushdown(int x,int l,int r)
{
    if (l==r||t[x].lazy==-1) return;
    int lazy=t[x].lazy;
    int mid=(l+r)>>1;
    t[x].lazy=-1;
    if (!lazy)
    {
        t[x<<1].lazy=t[x<<1|1].lazy=lazy;
        t[x<<1].lb=l;
        t[x<<1].rb=mid;
        t[x<<1].sb=mid-l+1;
        t[x<<1|1].lb=mid+1;
        t[x<<1|1].rb=r;
        t[x<<1|1].sb=r-mid;
    }
    else
    {
        t[x<<1].lazy=t[x<<1|1].lazy=lazy;
        t[x<<1].lb=t[x<<1].rb=t[x<<1].sb=0;
        t[x<<1|1].lb=t[x<<1|1].rb=t[x<<1|1].sb=0;
    }
}
inline void build(int x,int l,int r)
{
    if (l==r)
    {
        t[x].s=a[l];
        t[x].rb=t[x].lb=l;
        t[x].sb=1,t[x].lazy=-1;
        return;
    }
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x,l,r);
}
inline void ins(int x,int l,int r,int pos,int v)
{   
    pushdown(x,l,r);
    if (l==r)
    {
        t[x].s+=1ll*v;
        return;
    }
    int mid=(l+r)>>1;
    if (pos<=mid)ins(x<<1,l,mid,pos,v);
    else ins(x<<1|1,mid+1,r,pos,v);
    pushup(x,l,r);
}
inline void change(int x,int l,int r,int l1,int r1,int ok)
{
    //if (l1>r1)return; 

    if (l==l1&&r==r1)
    {
        t[x].lazy=ok;
        if (!ok)t[x].lb=l,t[x].rb=r,t[x].sb=r-l+1;
        else t[x].lb=t[x].rb=t[x].sb=0;
        return;
    }pushdown(x,l,r);
    int mid=(l+r)>>1;
    if (r1<=mid)change(x<<1,l,mid,l1,r1,ok);
    else if (l1>mid)change(x<<1|1,mid+1,r,l1,r1,ok);
    else
    {
        change(x<<1,l,mid,l1,mid,ok);
        change(x<<1|1,mid+1,r,mid+1,r1,ok);
    }
    //change(x<<1,l,mid,l1,min(r1,mid),ok);
    //change(x<<1|1,mid+1,r,max(l1,mid+1),r1,ok);
    pushup(x,l,r);
}
inline int query(int x,int l,int r,ll kth)
{
    if (l==r)return l;
    int mid=(l+r)>>1;
    if (t[x<<1].s>=kth)return query(x<<1,l,mid,kth);
    else return query(x<<1|1,mid+1,r,kth-t[x<<1].s);
}
node getlb(int x,int l,int r,int l1,int r1)
{
    node ans;
    if (!t[x].sb||l1>r1)return ans=(node){0,inf};
    pushdown(x,l,r);
    if (l==r)return ans=(node){l,0};
    int mid=(l+r)>>1;
    if (t[x<<1].rb&&t[x<<1].rb>=l1)
    {
        node ans=getlb(x<<1,l,mid,l1,min(mid,r1));
        if (ans.x)
        ans.y+=t[x<<1|1].tol+1ll*t[x<<1|1].s*(mid-ans.x+1);
        return ans;
    }
    else
    {
        node ans=getlb(x<<1|1,mid+1,r,max(l1,mid+1),r1);
        if (ans.x)
        ans.y+=t[x<<1].tor+1ll*t[x<<1].s*(ans.x-mid);
        return ans;
    }
}
node getrb(int x,int l,int r,int l1,int r1)
{
    node ans;
    if (!t[x].sb||l1>r1)return ans=(node){0,inf};
    pushdown(x,l,r);
    if (l==r)return ans=(node){l,0};
    int mid=(l+r)>>1;
    if (t[x<<1|1].lb&&t[x<<1|1].lb<=r1)
    {
        node ans=getrb(x<<1|1,mid+1,r,max(l1,mid+1),r1);
        if (ans.x)
        ans.y+=t[x<<1].tor+1ll*t[x<<1].s*(ans.x-mid);
        return ans;
    }
    else
    {
        node ans=getrb(x<<1,l,mid,l1,min(mid,r1));
        if (ans.x)
        ans.y+=t[x<<1|1].tol+1ll*t[x<<1|1].s*(mid-ans.x+1);
        return ans;
    }
}
int main()
{
    freopen("position.in","r",stdin);
    freopen("position.out","w",stdout);
    n=read(),m=read();
    ll tot=0;
    fo(i,1,n)a[i]=read(),tot+=a[i];
    build(1,1,n);
    while(m--)
    {
        int op=read(),x=read(),y=read();
        if (op==1)ins(1,1,n,x,y),tot+=y;
        if (op==2)ins(1,1,n,x,-y),tot-=y;
        if (op==3)change(1,1,n,x,y,0);
        if (op==4)change(1,1,n,x,y,1);
        int mid=query(1,1,n,(tot+1)/2);
        node l=getrb(1,1,n,1,mid);
        node r=getlb(1,1,n,mid,n);
        if (!l.x&&!r.x)printf("-1\n");
        else 
        {
            if (l.y<=r.y)printf("%d\n",l.x);
            else printf("%d\n",r.x);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值