Loj6515「雅礼集训 2018 Day10」贪玩蓝月(线段树分治)
这是基于时间的离线线段树分治法,时间分治是一种经典套路,一般来说,离线算法比在线算法容易实现。
因此在本题,我们用双端队列维护信息,弹出来的时候,在时间线段树上区间修改,表示他在哪段时间可见,这样我们查询的时候,在所需要查询的时间,那里就是合法的信息
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; typedef pair<pair<int,int>,int> plll; const int N=1e5+10; const int mod=1e9+7; int m,p; struct node{ int l,r; vector<pll> num; }tr[N<<2]; pll ans[N]; int vis[N]; ll f[N][550]; int cnt; void build(int u,int l,int r){ if(l==r){ tr[u]={l,r}; } else{ tr[u]={l,r}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } } void modify(int u,int l,int r,pll x){ if(tr[u].l>=l&&tr[u].r<=r){ tr[u].num.push_back(x); return ; } int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,r,x); if(r>mid) modify(u<<1|1,l,r,x); } void query(int u){ int tmp=cnt; int i,j; for(i=0;i<(int)tr[u].num.size();i++){ for(j=0;j<p;j++){ //相加永远不可能超过2p,所以不用担心是否会遗漏情况,直接更新即可 f[cnt+i+1][(j+tr[u].num[i].first)%p]=max(f[cnt+i][(j+tr[u].num[i].first)%p],f[cnt+i][j]+tr[u].num[i].second); } } cnt+=(int)tr[u].num.size(); if(tr[u].l==tr[u].r){ if(vis[tr[u].l]){ ll res=-0x3f3f3f3f; for(int i=ans[tr[u].l].first;i<=ans[tr[u].r].second;i++){ res=max(res,f[cnt][i]); } if(res==-0x3f3f3f3f){ cout<<-1<<endl; } else{ cout<<res<<endl; } } cnt=tmp; return ; } query(u<<1); query(u<<1|1); cnt=tmp; } int main(){ ios::sync_with_stdio(false); int d; cin>>d; cin>>m>>p; build(1,1,m); int i; deque<plll> q; for(i=1;i<=m;i++){ string s; cin>>s; int a,b; if(s=="IF"){ cin>>a>>b; q.push_front({{a%p,b},i}); } else if(s=="IG"){ cin>>a>>b; q.push_back({{a%p,b},i}); } else if(s=="DF"){ modify(1,q.front().second,i-1,q.front().first); q.pop_front(); } else if(s=="DG"){ modify(1,q.back().second,i-1,q.back().first); q.pop_back(); } else{ cin>>a>>b; vis[i]=1; ans[i]={a,b}; } } while(q.size()){ auto tmp=q.front(); q.pop_front(); modify(1,tmp.second,m,tmp.first); } memset(f,-0x3f,sizeof f); f[0][0]=0; query(1); }
没有人不辛苦,只有人不喊疼