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; }