BZOJ3878 AHOI2014 奇怪的计算器 线段树

Orz http://www.cnblogs.com/wuyuhan/p/5245879.html

离散化之后线段树维护,由于修改后数相对大小并不变化,因此可以找到<=L和>=R开始的位置单独维护。

很简单的思路……但是标记修改真的把我恶心到了……wuyuhan的BLOG里讲得方法我给9分,差一分是怕他骄傲(明明自己已经弱爆了QAQ)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

const int MAXN=100000+2;
int n,m,h[MAXN],p[MAXN];
ll SL,SR,L,R,s[MAXN],xx[MAXN];
struct tag{
    long long a,b,c;
    void clear(){ a=1,b=c=0;}
    void operator+=(tag o){ a=a*o.a,b=b*o.a+o.b,c=c*o.a+o.c;}
    long long calc(long long x){ return min(max(L,x*(a+b)+c),R);}
};
struct tree{
    tag l,r,la;
    tree(){l.clear(),r.clear(),la.clear();}
}t[3*MAXN];

bool cmp(int a,int b){ return xx[a]<xx[b];}

void down(int x,int l,int r){
    if(l>=r)return;
    t[x*2].la+=t[x].la,t[x*2].l+=t[x].la,t[x*2].r+=t[x].la;
    t[x*2+1].la+=t[x].la,t[x*2+1].l+=t[x].la,t[x*2+1].r+=t[x].la;
    t[x].la.clear();
}

void solve(int x,int l,int r){
    if(t[x].r.calc(xx[h[r]])!=R&&t[x].l.calc(xx[h[l]])!=L)return;

    down(x,l,r);
    if(t[x].l.calc(xx[h[l]])==R){t[x].l=t[x].r=t[x].la=(tag){0,0,R};return;}
    if(t[x].r.calc(xx[h[r]])==L){t[x].l=t[x].r=t[x].la=(tag){0,0,L};return;}

    solve(x*2,l,l+r>>1),solve(x*2+1,(l+r>>1)+1,r);
    t[x].l=t[x*2].l,t[x].r=t[x*2+1].r;
}

void solve2(int x,int l,int r){
    down(x,l,r);
    if(l!=r) solve2(x*2,l,l+r>>1),solve2(x*2+1,(l+r>>1)+1,r);
    else xx[h[l]]=t[x].l.calc(xx[h[l]]);
}

int main(){
    cin >> n >> L >> R;
    for(int i=1;i<=n;i++){
        char z[3];
        scanf("%s",z),cin >> s[i];

        if(z[0]=='+')p[i]=1;
        if(z[0]=='-')p[i]=2;
        if(z[0]=='*')p[i]=3;
        if(z[0]=='@')p[i]=4;
    }
    cin >> m;
    for(int i=1;i<=m;i++) cin >> xx[i],h[i]=i;
    sort(&h[1],&h[m+1],cmp);

    tag v;
    for(int i=1;i<=n;i++){
        if(p[i]==1)v=(tag){1,0,s[i]};
        if(p[i]==2)v=(tag){1,0,-s[i]};
        if(p[i]==3)v=(tag){s[i],0,0};
        if(p[i]==4)v=(tag){1,s[i],0};

        t[1].la+=v,t[1].l+=v,t[1].r+=v;
        solve(1,1,m);
    }

    solve2(1,1,m);
    for(int i=1;i<=m;i++) printf("%d\n",(int)xx[i]);

    return 0;
}


你可能感兴趣的:(BZOJ3878 AHOI2014 奇怪的计算器 线段树)