【BZOJ3878】【Ahoi2014】奇怪的计算器 维护区间性质。线段树

广告:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44037685");
}

题解:

先排序然后插入线段树
用线段树每次对全区间进行操作。
然后维护哪些段区间溢出了,对这段区间进行赋值。

溢出处理:

一个区间的左端点大于最大值,或者右端点小于最小值
那么这个区间就该被覆盖。

覆盖,加特技:

乘0+x就是覆盖成x。

剪枝?:

一个区间右端点 最大值,或者左端点 最小值,那么return

数据一组:

3 3 3044
- 9999
@ 3
- 1367
2
850
127

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101000
#define ls (note<<1)
#define rs (note<<1|1)
using namespace std;
struct LSH
{
    long long x;
    int p;
    bool operator < (const LSH &a)const 
    {return x<a.x;}
    void read(int n){scanf("%lld",&x),p=n;}
}lsh[N];
struct OPT
{
    int f;
    long long a;
    void read(int p){scanf("%lld",&a),f=p;}
}opt[N];
int n,m;
long long L,R,ans[N];
struct KSD
{
    int l,r,s;
    long long A,B,C;
    long long L,R,lx,rx;
}s[N<<2];
inline void pushdown(int note) // 乘法C不影响其它
{
    if(s[note].C!=1)
    {
        s[note].L*=s[note].C;
        s[note].R*=s[note].C;

        if(s[note].l<s[note].r)
        {
            s[ls].A*=s[note].C;
            s[ls].B*=s[note].C;
            s[ls].C*=s[note].C;
            s[rs].A*=s[note].C;
            s[rs].B*=s[note].C;
            s[rs].C*=s[note].C;
        }

        s[note].C=1;
    }
    if(s[note].A)
    {
        s[note].L+=s[note].A;
        s[note].R+=s[note].A;

        if(s[note].l<s[note].r)
        {
            s[ls].A+=s[note].A;
            s[rs].A+=s[note].A;
        }

        s[note].A=0;
    }
    if(s[note].B)
    {
        s[note].L+=s[note].B*s[note].lx;
        s[note].R+=s[note].B*s[note].rx;

        if(s[note].l<s[note].r)
        {
            s[ls].B+=s[note].B;
            s[rs].B+=s[note].B;
        }

        s[note].B=0;
    }
    return ;
}
inline void pushup(int note)
{
    s[note].L=s[ls].L;
    s[note].R=s[rs].R;
    return ;
}
void build(int note,int l,int r)
{
    s[note].l=l,s[note].r=r;
    s[note].C=1;
    if(l==r)
    {
        s[note].L=s[note].R=s[note].lx=s[note].rx=lsh[l].x;
        s[note].s=lsh[l].p;
        return ;
    }
    int mid=l+r>>1;
    build(ls,l,mid),build(rs,mid+1,r);
    s[note].lx=s[ls].lx,s[note].rx=s[rs].rx;
    pushup(note);
    return ;
}
void add(int note,long long w,int f)
{
    if(f==0)s[note].A+=w;
    else s[note].B+=w;
    pushdown(note);
}
void mul(int note,long long w)
{
    s[note].A*=w,s[note].B*=w,s[note].C*=w;
    pushdown(note);
}
// void cover(x) -> mul(0),add(x,0)
void keep(int note)
{
    pushdown(note);
    if(s[note].L>R)
    {
        s[note].A=R;
        s[note].B=0;
        s[note].C=0;
        pushdown(note);
        return ;
    }
    if(s[note].R<L)
    {
        s[note].A=L;
        s[note].B=0;
        s[note].C=0;
        pushdown(note);
        return ;
    }
    if(s[note].R<=R&&s[note].L>=L)return ;
    int mid=s[note].l+s[note].r>>1;
    keep(ls),keep(rs),pushup(note);
}
void dfs(int note)
{
    pushdown(note);
    if(s[note].l==s[note].r)
    {
        ans[s[note].s]=s[note].L;
        return ;
    }
    dfs(ls),dfs(rs);
}
char ss[5];
int main()
{
    freopen("test.in","r",stdin);

    int i;
    scanf("%d%lld%lld",&m,&L,&R);
    for(i=1;i<=m;i++)
    {
        scanf("%s",ss);
        if(ss[0]=='+')opt[i].read(1);
        else if(ss[0]=='-')opt[i].read(2);
        else if(ss[0]=='*')opt[i].read(3);
        else if(ss[0]=='@')opt[i].read(4);
    }
    scanf("%d",&n);
    for(i=1;i<=n;i++)lsh[i].read(i);
    sort(lsh+1,lsh+n+1);
    build(1,1,n);
    for(i=1;i<=m;i++)
    {
        if(opt[i].f==1)add(1,opt[i].a,0);
        else if(opt[i].f==2)add(1,-opt[i].a,0);
        else if(opt[i].f==3)mul(1,opt[i].a);
        else if(opt[i].f==4)add(1,opt[i].a,1);
        keep(1);
    }
    dfs(1);
    for(i=1;i<=n;i++)printf("%lld\n",ans[i]);
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值