P4041 [AHOI2014/JSOI2014]奇怪的計算器
阿新 • • 發佈:2021-08-30
一個 \(O(n\log^2 n)\) 的神奇做法。
這道題和那個 P4588 數學計算很像,所以能想到把所有數儲存起來做操作。
先想想上下界。我們珂以先排序,線段樹維護 Min,Max,再二分要修改的位置,二分出來後區間賦值。珂以用線段樹。(這裡我的區間賦值是先乘 \(0\) 再加值)
這樣 \(O(n\log^2n)\) 的複雜度:
inline void erfen1(){ int le=1,ri=q; while(le<=ri){ int Mid=le+ri>>1; if(query2(1,1,q,1,Mid)<=L)le=Mid+1; else ri=Mid-1; } if(le>=2){ modify2(1,1,q,1,le-1,0); modify1(1,1,q,1,le-1,L); } } inline void erfen2(){ int le=1,ri=q; while(le<=ri){ int Mid=le+ri>>1; if(query3(1,1,q,Mid,q)>=R)ri=Mid-1; else le=Mid+1; } if(ri<=q-1){ modify2(1,1,q,ri+1,q,0); modify1(1,1,q,ri+1,q,R); } }
第一、二、三個加法、減法、乘法操作也可以線段樹。
第四個珂以想到用另一棵線段樹處理一下原數列區間最小、大值,再打標記。
但其實不需要。
因為排過序,而乘法的數字都大於零,所以相對位置不會改變。
所以我們珂以直接取左/右端點。
就是這樣:
inline void GAN(int k,int l,int r,int v){
xds2[k]+=a[r].x*v;
xds3[k]+=a[l].x*v;
gan[k]+=v;
}
最後,吸口老氧就可以快樂地跑過去了。
YJX AK IOI#include<bits/stdc++.h> using namespace std;//add mul gan min max sum #define int long long const int maxn=1e5+5; int xds2[maxn<<2]/*最大*/,xds3[maxn<<2]/*最小*/,add[maxn<<2],mul[maxn<<2],gan[maxn<<2],ans[maxn]; int op[maxn],num[maxn],n,L,R,q;//gan是操作4 struct nice{ int x,id; bool operator <(const nice &b)const{return x<b.x;} }a[maxn]; #define ls (k<<1) #define rs (k<<1|1) #define mid (l+r>>1) inline void pushup(int k){ xds2[k]=max(xds2[ls],xds2[rs]); xds3[k]=min(xds3[ls],xds3[rs]); } inline void GAN(int k,int l,int r,int v){ xds2[k]+=a[r].x*v; xds3[k]+=a[l].x*v; gan[k]+=v; } inline void ADD(int k,int l,int r,int v){ xds2[k]+=v,xds3[k]+=v; add[k]+=v; } inline void MUL(int k,int l,int r,int v){ xds2[k]*=v,xds3[k]*=v,add[k]*=v,mul[k]*=v;gan[k]*=v; } void build(int k,int l,int r){ mul[k]=1; if(l==r){ xds2[k]=xds3[k]=a[l].x; return ; } build(ls,l,mid); build(rs,mid+1,r); pushup(k); } inline void pushdown(int k,int l,int r){ if(mul[k]!=1){ MUL(ls,l,mid,mul[k]); MUL(rs,mid+1,r,mul[k]); mul[k]=1; } if(add[k]!=0){ ADD(ls,l,mid,add[k]); ADD(rs,mid+1,r,add[k]); add[k]=0; } if(gan[k]!=0){ GAN(ls,l,mid,gan[k]); GAN(rs,mid+1,r,gan[k]); gan[k]=0; } } void modify1(int k,int l,int r,int x,int y,int v){ if(x<=l&&r<=y)return ADD(k,l,r,v); pushdown(k,l,r); if(x<=mid)modify1(ls,l,mid,x,y,v); if(mid<y)modify1(rs,mid+1,r,x,y,v); pushup(k); } void modify2(int k,int l,int r,int x,int y,int v){ if(x<=l&&r<=y)return MUL(k,l,r,v); pushdown(k,l,r); if(x<=mid)modify2(ls,l,mid,x,y,v); if(mid<y)modify2(rs,mid+1,r,x,y,v); pushup(k); } void modify3(int k,int l,int r,int x,int y,int v){ if(x<=l&&r<=y)return GAN(k,l,r,v); pushdown(k,l,r); if(x<=mid)modify3(ls,l,mid,x,y,v); if(mid<y)modify3(rs,mid+1,r,x,y,v); pushup(k); } int query(int k,int l,int r,int x){ if(l==r)return xds2[k]; pushdown(k,l,r); if(x<=mid)return query(ls,l,mid,x); else return query(rs,mid+1,r,x); } int query2(int k,int l,int r,int x,int y){ if(x<=l&&r<=y)return xds2[k]; pushdown(k,l,r); int res=-0x3f3f3f3f3f3f3f3f; if(x<=mid)res=max(res,query2(ls,l,mid,x,y)); if(mid<y)res=max(res,query2(rs,mid+1,r,x,y)); return res; } int query3(int k,int l,int r,int x,int y){ if(x<=l&&r<=y)return xds3[k]; pushdown(k,l,r); int res=0x3f3f3f3f3f3f3f3f; if(x<=mid)res=min(res,query3(ls,l,mid,x,y)); if(mid<y)res=min(res,query3(rs,mid+1,r,x,y)); return res; } inline void erfen1(){ int le=1,ri=q; while(le<=ri){ int Mid=le+ri>>1; if(query2(1,1,q,1,Mid)<=L)le=Mid+1; else ri=Mid-1; } if(le>=2){ modify2(1,1,q,1,le-1,0); modify1(1,1,q,1,le-1,L); } } inline void erfen2(){ int le=1,ri=q; while(le<=ri){ int Mid=le+ri>>1; if(query3(1,1,q,Mid,q)>=R)ri=Mid-1; else le=Mid+1; } if(ri<=q-1){ modify2(1,1,q,ri+1,q,0); modify1(1,1,q,ri+1,q,R); } } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>L>>R; for(int i=1;i<=n;i++){ char c; cin>>c>>num[i]; if(c=='+'){ op[i]=1; } if(c=='-'){ op[i]=1,num[i]=-num[i]; } if(c=='*'){ op[i]=2; } if(c=='@'){ op[i]=3; } } cin>>q; for(int i=1;i<=q;i++)cin>>a[i].x,a[i].id=i; sort(a+1,a+q+1); build(1,1,q); for(int i=1;i<=n;i++){ if(op[i]==1)ADD(1,1,q,num[i]); if(op[i]==2)MUL(1,1,q,num[i]); if(op[i]==3)GAN(1,1,q,num[i]); erfen1(); erfen2(); } for(int i=1;i<=q;i++)ans[a[i].id]=query(1,1,q,i); for(int i=1;i<=q;i++)cout<<ans[i]<<endl; return 0; }