uoj218_火车管理
题意
\(n\)个位置,每个位置一个栈,三种操作,询问区间栈顶的和,区间入栈某个数,单点出栈某个数。
分析
- 用一个线段树来维护栈顶的和,区间(单点)更新和区间询问。
- 用一个主席树来维护每个位置最新一次入栈的时间,即主席树存的是时间,然后取出的时间也能作为主席树的下标来访问对应时间的版本。
- 因此区间入栈的时候区间更新线段树和区间更新主席树。
- 单点出栈时,先查询这个位置栈顶元素的入栈时间,然后再用这个时间的上一个版本的主席树查询栈顶下一个元素的入栈时间,根据入栈时间可以知道入栈的元素,然后由于栈顶已经出栈,所以新的栈顶就是该元素,单点更新线段树和主席树。
代码
#include <bits/stdc++.h>
#define ls i<<1
#define rs i<<1|1
#define mid (l+r)/2
using namespace std;
typedef long long ll;
const int N=8e5+50;
int n,m,ty,o,l1,r1,x[N];
struct ST{
//lz:区间赋值标记 sum:区间和
ll lz[N*4],sum[N*4];
void pushup(int i){
sum[i]=sum[ls]+sum[rs];
}
void pushdown(int i,int l,int r){
if(lz[i]){
lz[ls]=lz[i];
lz[rs]=lz[i];
sum[ls]=(mid-l+1)*lz[i];
sum[rs]=(r-mid)*lz[i];
lz[i]=0;
}
}
void update(int i,int l,int r,int ql,int qr,int v){
if(ql<=l && qr>=r){
lz[i]=v;
sum[i]=1ll*(r-l+1)*v;
return;
}
pushdown(i,l,r);
if(ql<=mid){
update(ls,l,mid,ql,qr,v);
}
if(qr>mid){
update(rs,mid+1,r,ql,qr,v);
}
pushup(i);
}
ll query(int i,int l,int r,int ql,int qr){
if(ql<=l && qr>=r){
return sum[i];
}
pushdown(i,l,r);
ll ans=0;
if(ql<=mid){
ans+=query(ls,l,mid,ql,qr);
}
if(qr>mid){
ans+=query(rs,mid+1,r,ql,qr);
}
return ans;
}
}st;
int tr[N];
struct CT{
int tot=0,tim[N*50],lr[N*50],rr[N*50];
int update(int pre,int l,int r,int ql,int qr,int t){
int rt=++tot;
tim[rt]=t;
lr[rt]=lr[pre];
rr[rt]=rr[pre];
if(ql<=l && qr>=r){
lr[rt]=rr[rt]=(l==r?0:rt);
}else{
if(ql<=mid){
lr[rt]=update(lr[pre],l,mid,ql,qr,t);
}
if(qr>mid){
rr[rt]=update(rr[pre],mid+1,r,ql,qr,t);
}
}
return rt;
}
int query(int i,int l,int r,int v){
if(l==r && l==v){
return tim[i];
}
if(v<=mid){
return query(lr[i],l,mid,v);
}else{
return query(rr[i],mid+1,r,v);
}
}
}ct;
int dec(int l1,int lst){
return (l1+lst*ty)%n+1;
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&m,&ty);
ll lst=0;
for(int t=1;t<=m;t++){
scanf("%d",&o);
tr[t]=tr[t-1];
if(o==1){
scanf("%d%d",&l1,&r1);
l1=dec(l1,lst);
r1=dec(r1,lst);
int l=min(l1,r1);
int r=max(l1,r1);
//直接查询线段树区间和
lst=st.query(1,1,n,l,r);
printf("%lld\n",lst);
}else if(o==2){
scanf("%d",&l1);
int l=dec(l1,lst);
//查询l这个位置最新插入的时间
int tm=ct.query(tr[t],1,n,l);
//查询再前一个插入时间,即将最新插入出栈
int pt=ct.query(tr[tm-1],1,n,l);
//线段树单点修改为上一个版本
st.update(1,1,n,l,l,x[pt]);
//主席树对当前最新版本单点修改l位置的插入时间
tr[t]=ct.update(tr[t],1,n,l,l,pt);
}else if(o==3){
scanf("%d%d%d",&l1,&r1,&x[t]);
l1=dec(l1,lst);
r1=dec(r1,lst);
int l=min(l1,r1);
int r=max(l1,r1);
//线段树区间更新
st.update(1,1,n,l,r,x[t]);
//前面已经有tr[t]=tr[t-1] 无论更不更新都复制一个新版本
//主席树区间更新
tr[t]=ct.update(tr[t],1,n,l,r,t);
}
}
return 0;
}
uoj218_火车管理的更多相关文章
- 【UNR #1】火车管理(主席树)
[UNR #1]火车管理(主席树) 好好的代码被 \(extra\ test\) 卡常了...我就放一个目前最快的版本吧... 题意简化: 有 \(n\) 个栈,\(m\) 次操作. 将 \(x\) ...
- 「UOJ218」火车管理
「UOJ218」火车管理 解题思路:观察发现,在弹出 \(x\) 之前,它前面这个元素都是保持不变的,所以可以用一棵可持久化线段树维护每一个栈顶元素的插入时间,每次找到当前时间\(-1\) 的版本就可 ...
- 【UNR #1】火车管理
题目描述 uoj 旗下有一个火车站,用来管理属于 uoj 的小火车. 火车站一共有 nn 条编号为 1,…,n1,…,n 的,只有一端的用来存放小火车的铁路,由于小火车特殊的构造,每条铁路可以停放无数 ...
- UOJ 218 火车管理
http://uoj.ac/problem/218 思路:建立一个可持久化线段树,代表这个位置的火车是哪辆,然后再弄一个线段树维护答案. 如果询问,直接询问线段树. 如果区间压入,直接在主席树上面压入 ...
- 【UOJ UNR #1】火车管理
来自FallDream的博客,未经允许,请勿转载,谢谢. 题面 考虑用可持久化线段树直接维护每个点在不同时刻,第一辆车的编号. 这样3操作就变成了区间赋值,1操作变成区间和 2操作的话,只需要查询一下 ...
- UOJ#218. 【UNR #1】火车管理 线段树 主席树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html 题解 如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖.区间求和 ...
- UOJ #218. 【UNR #1】火车管理
Description Solution 实际上添加问题就是一个线段树区间覆盖问题,打标记就好 对于弹栈操作比较难搞,实际上也就是一个历史查询,我们不需要保存栈中的每一个元素,我们通过查找历史状态就可 ...
- [UOJ218]火车管理
建一棵答案线段树存栈顶值,两棵可持久化线段树分别存栈顶值和栈顶元素入栈时间 询问就直接在答案线段树上查,弹栈就用入栈时间在对应版本的可持久化线段树上查询即可,修改就是可持久化线段树的区间覆盖 以前一直 ...
- 【UOJ UNR #1】火车管理 可持久化线段树
用可持久化线段树维护每个站的第一辆车和每个站的前一次更新的位置即可. #include<iostream> #include<cstring> #include<cstd ...
随机推荐
- 13.Python字符串详解(包含长字符串和原始字符串)
简单地理解,字符串就是“一串字符”,也就是用引号包裹的任何数据,比如“Hello,Charlie”是一个字符串,“12345”也是一个字符串. Python 要求,字符串必须使用引号括起来,可以使用单 ...
- R_Studio(学生成绩)使用cbind()函数对多个学期成绩进行集成
“Gary1.csv”.“Gary2.csv”.“Gary3.csv”中保存了一个班级学生三个学期的成绩 对三个学期中的成绩数据进行集成并重新计算综合成绩和排名,并按排名顺序排布(学号9位数11130 ...
- 创建Idea创建SpringBoot项目 - 各个目录的解释
[SpringBoot-创建项目]一.通过Idea创建SpringBoot项目 一.首先我们通过Idea创建一个新项目 二.选择sdk和快速构建模板 三.填写项目基本信息 三.选择项目依赖 四.填写项 ...
- watir学习系列--对话框处理(转)
1.下面是网上编写的类库,保存为libAutoit.rb #LibAutoit主要处理windows弹出的对话框,调用autoit类进行处理 #函数如下: #- ChooseFileDialog函数: ...
- iframe标签的初试
要使用的框架的页面代码: <body> <form id="form1" runat="server"> <div> < ...
- Parcelable和Serializable
本文主要介绍Parcelable和Serializable的作用.效率.区别及选择,关于Serializable的介绍见Java 序列化的高级认识. 1.作用 Serializable的作用是为了保存 ...
- javascript - 事件详解(阻止事件冒泡+阻止事件行为)
一.事件流 1.事件流 描述的是在页面中接受事件的顺序 2.事件冒泡 由最具体的元素接收,然后逐级向上传播至最不具体的元素的节点 (最具体 –> 最不具体) 3.事件捕获 最不具体的节点先接收事 ...
- Kotlin之定义函数
java: int add (int m ,int n){ return m+n; } void process(int m){ Systrm.out.println(m); } kotlin: fu ...
- React之js实现跳转路由
1.新增知识 /* 实现js跳转路由:https://reacttraining.com/react-router/web/example/auth-workflow 1.要引入Redirect im ...
- C#规范整理·多线程\异步\并行\任务
有一个领域的工作处理起来几乎总是最棘手的,这就是多线程编码.多线程编码是所有开发人员前进途中的一个坎,现在,该是尝试克服它的时候了. 1.区分异步和多线程应用场景 先看一个例子 private voi ...