BZOJ3878 AHOI2014 奇怪的计算器 线段树
题意:
给定N个操作,每种操作的格式为:
1、+a:表示将当前的结果加上a
2、-a:表示将当前的结果减去a
3、*a:表示将当前的结果乘以a
4、@a:表示将当前的结果加上a*X(X是一开始JYY输入的数)
在操作中,如果结果>R,则结果=R;如果结果<L,则结果=L。给定M个xi,求每个x在经过这N个操作之后的结果是多少
题解:
Orz wuyuhan
离散化之后线段树维护,由于修改后数相对大小并不变化,因此可以找到<=L和>=R开始的位置单独维护。
#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; }