[uoj218]火车管理——主席树

题目大意

维护一个栈,每次区间压栈,单点弹栈,区间询问栈顶的元素和。

思路

如果没有弹栈的操作的话,我们每一次只需要在一颗线段树上面区间赋值即可。

加上弹栈操作,我们每次就需要知道当前栈顶元素的上一个元素是什么,考虑用主席树来维护每一个时刻每一个位置的最近一次的修改位置。

假设当前的时间为x且我们需要弹栈,那么我们需要先查询得到最近的一次时间y,然后查询y-1的修改时间z,那么我们就得到了栈顶下面的元素的修改时间。

然后我们需要将x点的这个元素的时间改为z,然后更新查询线段树上的答案即可。

不难发现我们实际上是向前维护了一个最近修改时间的链表,由于主席树的继承性质,直接查询y-1使得我们的答案是正确的。

/*=======================================
 * Author : ylsoi
 * Time : 2019.3.10
 * Problem : uoj218
 * E-mail : ylsoi@foxmail.com
 * ====================================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
#define mid ((l+r)>>1)
typedef long long ll;

using namespace std;

void File(){
    freopen("uoj218.in","r",stdin);
    freopen("uoj218.out","w",stdout);
}

template<typename T>void read(T &_){
    _=0; T f=1; char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    _*=f;
}

string proc(){
    ifstream f("/proc/self/status");
    return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
}

const int maxn=5e5+10;
int n,m,ty,ans,root[maxn],tot,w[maxn];

struct Segment_Tree{
#define lc o<<1
#define rc o<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
    int val[maxn<<2],sum[maxn<<2],las[maxn<<2];
    void pushdown(int o,int l,int r){
        if(las[o])las[lc]=las[rc]=las[o],las[o]=0;
        if(val[o]){
            val[lc]=val[rc]=val[o];
            sum[lc]=(mid-l+1)*val[o];
            sum[rc]=(r-mid)*val[o];
            val[o]=0;
        }
    }
    void update(int o,int l,int r,int L,int R,int x,int y){
        if(L<=l && r<=R)val[o]=x,sum[o]=(r-l+1)*x,las[o]=y;
        else{
            pushdown(o,l,r);
            if(L<=mid)update(lson,L,R,x,y);
            if(R>=mid+1)update(rson,L,R,x,y);
            sum[o]=sum[lc]+sum[rc];
        }
    }
    int query_sum(int o,int l,int r,int L,int R){
        if(L<=l && r<=R)return sum[o];
        else{
            pushdown(o,l,r);
            int ret=0;
            if(L<=mid)ret+=query_sum(lson,L,R);
            if(R>=mid+1)ret+=query_sum(rson,L,R);
            return ret;
        }
    }
    int query_las(int o,int l,int r,int p){
        if(l==r)return las[o];
        pushdown(o,l,r);
        if(p<=mid)return query_las(lson,p);
        else return query_las(rson,p);
    }
#undef lc
#undef rc
}T1;

struct Chairman_Tree{
    int cnt;
    struct node{int val,lc,rc;}t[maxn*120];
    void insert(int &o,int l,int r,int L,int R,int x){
        int now=++cnt;
        t[now]=t[o],o=now,t[o].val=x;
        if(L<=l && r<=R)t[o].lc=t[o].rc=(l==r ? 0 : o);
        else{
            if(L<=mid)insert(t[o].lc,l,mid,L,R,x);
            if(R>=mid+1)insert(t[o].rc,mid+1,r,L,R,x);
        }
    }
    int query(int o,int l,int r,int p){
        if(l==r)return t[o].val;
        if(p<=mid)return query(t[o].lc,l,mid,p);
        else return query(t[o].rc,mid+1,r,p);
    }
}T2;

int main(){
    //File();

    read(n),read(m),read(ty);

    int op,l,r,x;

    /*T1.update(1,1,n,1,2,1,1);
    cout<<T1.query_sum(1,1,n,4,5)<<endl;
    REP(i,1,n)printf("%d ",T1.query_sum(1,1,n,i,i));
    printf("\n");*/

    REP(i,1,m){
        read(op);
        if(op==1){
            read(l),read(r);
            l=(l+ans*ty)%n+1;
            r=(r+ans*ty)%n+1;
            if(l>r)swap(l,r);
            printf("%d\n",ans=T1.query_sum(1,1,n,l,r));
        }
        else if(op==2){
            read(l);
            l=(l+ans*ty)%n+1;
            int tim=T1.query_las(1,1,n,l);
            if(tim){
                int las=T2.query(root[tim-1],1,n,l);
                ++tot;
                root[tot]=root[tot-1];
                T2.insert(root[tot],1,n,l,l,las);
                T1.update(1,1,n,l,l,w[las],las);
            }
        }
        else{
            read(l),read(r),read(x);
            l=(l+ans*ty)%n+1;
            r=(r+ans*ty)%n+1;
            if(l>r)swap(l,r);
            w[++tot]=x;
            root[tot]=root[tot-1];
            T2.insert(root[tot],1,n,l,r,tot);
            T1.update(1,1,n,l,r,x,tot);
        }
        /*REP(j,1,n)printf("%d ",T1.query_sum(1,1,n,j,j));
        printf("\n");*/
    }

    //cerr<<proc()<<endl;

    return 0;
}

转载于:https://www.cnblogs.com/ylsoi/p/10513455.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值