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);
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/14120156.html