原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html
题解
如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖、区间求和的线段树上完成这个问题。
于是本题的重点转到了如何求新的栈顶。
考虑用一个主席树维护一下每一个时刻每一个位置的栈顶元素的进栈时间,那么新的栈顶就是 当前位置栈顶的进栈时间-1 这时候的栈顶元素,然后这个东西也可以用我们维护的进栈时间来得到,所以我们只需要弄一个支持区间覆盖单点查询历史版本的主席树;这里区间覆盖有一个小技巧:假设节点 x 所代表的区间都被覆盖了,那么修改完 val[x] 之后令 ls[x] = rs[x] = x 即可。
代码
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
using namespace std;
typedef long long LL;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=500005;
int n,m,k;
int lastans=0;
int hisv[N];
namespace seg{
const int S=N<<2;
int sum[S],add[S],len[S];
void build(int rt,int L,int R){
len[rt]=R-L+1,sum[rt]=add[rt]=0;
if (L==R)
return;
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
build(ls,L,mid);
build(rs,mid+1,R);
}
void pushdown(int rt){
int ls=rt<<1,rs=ls|1;
if (add[rt]){
add[ls]=add[rs]=add[rt];
sum[ls]=add[rt]*len[ls];
sum[rs]=add[rt]*len[rs];
add[rt]=0;
}
}
void update(int rt,int L,int R,int xL,int xR,int v){
if (R<xL||L>xR)
return;
if (xL<=L&&R<=xR){
sum[rt]=v*len[rt];
add[rt]=v;
return;
}
pushdown(rt);
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
update(ls,L,mid,xL,xR,v);
update(rs,mid+1,R,xL,xR,v);
sum[rt]=sum[ls]+sum[rs];
}
int Query(int rt,int L,int R,int xL,int xR){
if (R<xL||L>xR)
return 0;
if (xL<=L&&R<=xR)
return sum[rt];
pushdown(rt);
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
return Query(ls,L,mid,xL,xR)+Query(rs,mid+1,R,xL,xR);
}
}
namespace pt{
const int S=N*100;
int val[S],ls[S],rs[S],root[N],cnt;
void init(){
root[0]=cnt=ls[1]=rs[1]=1;
val[1]=0;
}
void update(int prt,int &rt,int L,int R,int xL,int xR,int v){
if (R<xL||L>xR)
return;
if (rt==prt)
rt=++cnt,val[rt]=val[prt],ls[rt]=ls[prt],rs[rt]=rs[prt];
if (xL<=L&&R<=xR){
val[rt]=v;
ls[rt]=rs[rt]=rt;
return;
}
int mid=(L+R)>>1;
update(ls[prt],ls[rt],L,mid,xL,xR,v);
update(rs[prt],rs[rt],mid+1,R,xL,xR,v);
}
int Query(int rt,int L,int R,int x){
if (L==R)
return val[rt];
int mid=(L+R)>>1;
if (x<=mid)
return Query(ls[rt],L,mid,x);
else
return Query(rs[rt],mid+1,R,x);
}
}
using pt::root;
int main(){
n=read(),m=read(),k=read();
seg::build(1,1,n);
pt::init();
hisv[0]=0;
for (int T=1;T<=m;T++){
root[T]=root[T-1];
int type=read(),L=(read()+lastans*k)%n+1,R,x;
if (type==1){
R=(read()+lastans*k)%n+1;
if (L>R)
swap(L,R);
printf("%d\n",lastans=seg::Query(1,1,n,L,R));
}
else if (type==2){
int t1=pt::Query(root[T-1],1,n,L);
t1=pt::Query(root[max(t1-1,0)],1,n,L);
seg::update(1,1,n,L,L,hisv[t1]);
pt::update(root[T-1],root[T],1,n,L,L,t1);
}
else if (type==3){
R=(read()+lastans*k)%n+1,x=read();
if (L>R)
swap(L,R);
hisv[T]=x;
seg::update(1,1,n,L,R,x);
pt::update(root[T-1],root[T],1,n,L,R,T);
}
}
return 0;
}
UOJ#218. 【UNR #1】火车管理 线段树 主席树的更多相关文章
-
线段树简单入门 (含普通线段树, zkw线段树, 主席树)
线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...
-
学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))
函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...
-
线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题
“队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄> 线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...
-
Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)
先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...
-
Codeforces 765F Souvenirs 线段树 + 主席树 (看题解)
Souvenirs 我们将询问离线, 我们从左往右加元素, 如果当前的位置为 i ,用一棵线段树保存区间[x, i]的答案, 每次更新完, 遍历R位于 i 的询问更新答案. 我们先考虑最暴力的做法, ...
-
小结:线段树 &; 主席树 &; 树状数组
概要: 就是用来维护区间信息,然后各种秀智商游戏. 技巧及注意: 一定要注意标记的下放的顺序及影响!考虑是否有叠加或相互影响的可能! 和平衡树相同,在操作每一个节点时,必须保证祖先的tag已经完全下放 ...
-
BZOJ5011 [JXOI2017]颜色 【线段树 + 主席树】
题目链接 BZOJ5011 题解 一定只有我这种智障会用这么奇怪的方法做这道题.. 由题我们知道最后剩余的一定是一个区间,而且区间内的颜色不存在于区间外 所以我们的目的就是为了找到这样的区间的数量 区 ...
-
洛谷P3834 可持久化线段树(主席树)模板
题目:https://www.luogu.org/problemnew/show/P3834 无法忍受了,我要写主席树! 解决区间第 k 大查询问题,可以用主席树,像前缀和一样建立 n 棵前缀区间的权 ...
-
[学习笔记] 可持久化线段树&;主席树
众所周知,线段树是一个非常好用也好写的数据结构, 因此,我们今天的前置技能:线段树. 然而,可持久化到底是什么东西? 别急,我们一步一步来... step 1 首先,一道简化的模型: 给定一个长度为\ ...
随机推荐
-
Android基础总结(十)
内容提供者(掌握) 应用的数据库是不允许其他应用访问的 内容提供者的作用就是让别的应用访问到你的私有数据 自定义内容提供者,继承ContentProvider类,重写增删改查方法,在方法中写增删改查数 ...
-
Android中的四种动画(一)
TweenAnimation 变换动画(也叫作"补间动画"),有四种(alpha scale translate rote). FrameAnimation(也叫DrawableA ...
-
vue2.0 transition -- demo实践填坑
前言 vue1.0版本和2.0版本的过渡系统改变还是蛮彻底的,具体请自行详看文档介绍:https://vuefe.cn/v2/guide/migration.html#过渡.在使用2.0版本做过渡效果 ...
-
【转】SQL删除重复记录,只保留其中一条
SQL:删除重复数据,只保留一条用SQL语句,删除掉重复项只保留一条在几千条记录里,存在着些相同的记录,如何能用SQL语句,删除掉重复的呢 1.查找表中多余的重复记录,重复记录是根据单个字段(peop ...
-
sql server触发器中增删改判断
触发器生效逻辑 在Before或者After之后使用INSERT,DELETE,UPDATE 触发器内情况判断 插入 if exists(select 1 from inserted) and not ...
-
Cipher Message
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=34121#problem/C // File Name: c.cpp // Author: ...
-
ChangeServiceConfig2 function
ChangeServiceConfig2 function Changes the optional configuration parameters of a service. Syntax C ...
-
新浪新闻页面抓取(JAVA-Jsoup)
1.使用gradle建立工程: 工程格式如下: include ':spider-demo' rootProject.name = 'my-spider-demo' settings def void ...
-
使用 IntraWeb (35) - TIWJQueryWidget
可有可无的东西, 因为没有它也可以方便达成其目的, 使用它貌似更形象一些; 也可以通过它调用其他 js 库. 利用类似手段, 有人推出了 CGDevTools; 它主要是利用 JQuery 扩展而成, ...
-
ubuntu12 root账户自动登录
Ubuntu为了系统安全,root帐号的密码是随机的,如果临时需要提升至root权限以执行一些命令,需要使用sudo命令.产线上有几台使用Ubuntu的机器,因为使用者不固定,并且执行程序时需要使 用 ...