【UOJ #218. 【UNR #1】】火车管理 可持久化线段树
2016-07-19 15:35
204 查看
题目:
uoj 旗下有一个火车站,用来管理属于 uoj 的小火车。
火车站一共有 n
n
条编号为 1,…,n
1,…,n
的,只有一端的用来存放小火车的铁路,由于小火车特殊的构造,每条铁路可以停放无数辆小火车。每条铁路是相互独立的。
铁路是一个栈结构,后停放的小火车可以先出来。
每辆小火车有一个吨位 t
t
。
由于 NOI2016 即将到来,想要跟小火车正面作战的人多了起来,火车站管理员九条可怜每天需要处理很多事件。
事件可以概括成一下三种:
•1 l r 有人想跟铁路编号在 [l,r]
[l,r]
的每条铁路的第一辆可以开出来的小火车正面战斗,你需要统计这些小火车的吨位之和,没有火车的铁路不计入答案。
•2 l 编号为 l
l
的铁路开走一辆火车,如果这条铁路没有小火车则不开出。
•3 l r x 铁路编号在 [l,r]
[l,r]
的每条铁路都新停放一辆吨位为 x
x
的火车。
现在管理员九条可怜要去南海前线了,你需要替他管理火车站。
由于火车站很忙,所以你需要实时反馈信息,我们会用一些手段要求你强制在线,具体请看输入格式。
输入格式
输入第一行三个非负整数 n,m,ty
n,m,ty
表示铁路的数量和操作次数还有是否强制在线。
接下来 m
m
行,每行四个数或者三个数或者两个数表示一次操作。
为了实时反馈信息,你需要解密 l,r
l,r
,设读入的是 l1,r1
l1,r1
,则实际的值如下:
l2r2lr====(l1+lastans⋅ty)modn+1(r1+lastans⋅ty)modn+1min(l2,r2)max(l2,r2)
l2=(l1+lastans⋅ty)modn+1r2=(r1+lastans⋅ty)modn+1l=min(l2,r2)r=max(l2,r2)
lastans
lastans
表示上一次询问的答案,如果之前没有询问则为 0
0
。
当你进行的是第二类操作时,只需要令 l=(l1+lastans⋅ty)modn+1
l=(l1+lastans⋅ty)modn+1
即可。
输入数据保证 1≤l1,r1≤n
1≤l1,r1≤n
。
注意,我们并没有加密吨位和操作类型
输出格式
对于每个询问输出一行,一个非负整数表示答案。
样例一
input
10 10 0
3 1 5 3
1 1 6
3 1 7 1
1 1 9
1 1 6
3 1 5 2
1 3 6
1 3 9
3 1 7 6
2 1
output
15
7
6
7
8
http://uoj.ac/problem/218
题解:
我们可以针对时间建立一颗可持久化线段树,维护每个铁路每个时间的栈顶的吨位和栈顶火车的入栈时间。
我们再维护一颗线段树用来统计答案。
于是操作就只有三种了:
区间询问:直接在答案线段树里询问即可。
区间压数:在可持久化线段树上进行区间覆盖,然后在答案线段树上修改一下。
单点弹数:由于我们记录了入栈时间,查询到入站时间t后,我们可以查询t时刻前的树,查出当前点入栈之前的栈顶的信息,然后在答案线段树上和可持久化线段树上修改。
代码:
uoj 旗下有一个火车站,用来管理属于 uoj 的小火车。
火车站一共有 n
n
条编号为 1,…,n
1,…,n
的,只有一端的用来存放小火车的铁路,由于小火车特殊的构造,每条铁路可以停放无数辆小火车。每条铁路是相互独立的。
铁路是一个栈结构,后停放的小火车可以先出来。
每辆小火车有一个吨位 t
t
。
由于 NOI2016 即将到来,想要跟小火车正面作战的人多了起来,火车站管理员九条可怜每天需要处理很多事件。
事件可以概括成一下三种:
•1 l r 有人想跟铁路编号在 [l,r]
[l,r]
的每条铁路的第一辆可以开出来的小火车正面战斗,你需要统计这些小火车的吨位之和,没有火车的铁路不计入答案。
•2 l 编号为 l
l
的铁路开走一辆火车,如果这条铁路没有小火车则不开出。
•3 l r x 铁路编号在 [l,r]
[l,r]
的每条铁路都新停放一辆吨位为 x
x
的火车。
现在管理员九条可怜要去南海前线了,你需要替他管理火车站。
由于火车站很忙,所以你需要实时反馈信息,我们会用一些手段要求你强制在线,具体请看输入格式。
输入格式
输入第一行三个非负整数 n,m,ty
n,m,ty
表示铁路的数量和操作次数还有是否强制在线。
接下来 m
m
行,每行四个数或者三个数或者两个数表示一次操作。
为了实时反馈信息,你需要解密 l,r
l,r
,设读入的是 l1,r1
l1,r1
,则实际的值如下:
l2r2lr====(l1+lastans⋅ty)modn+1(r1+lastans⋅ty)modn+1min(l2,r2)max(l2,r2)
l2=(l1+lastans⋅ty)modn+1r2=(r1+lastans⋅ty)modn+1l=min(l2,r2)r=max(l2,r2)
lastans
lastans
表示上一次询问的答案,如果之前没有询问则为 0
0
。
当你进行的是第二类操作时,只需要令 l=(l1+lastans⋅ty)modn+1
l=(l1+lastans⋅ty)modn+1
即可。
输入数据保证 1≤l1,r1≤n
1≤l1,r1≤n
。
注意,我们并没有加密吨位和操作类型
输出格式
对于每个询问输出一行,一个非负整数表示答案。
样例一
input
10 10 0
3 1 5 3
1 1 6
3 1 7 1
1 1 9
1 1 6
3 1 5 2
1 3 6
1 3 9
3 1 7 6
2 1
output
15
7
6
7
8
http://uoj.ac/problem/218
题解:
我们可以针对时间建立一颗可持久化线段树,维护每个铁路每个时间的栈顶的吨位和栈顶火车的入栈时间。
我们再维护一颗线段树用来统计答案。
于是操作就只有三种了:
区间询问:直接在答案线段树里询问即可。
区间压数:在可持久化线段树上进行区间覆盖,然后在答案线段树上修改一下。
单点弹数:由于我们记录了入栈时间,查询到入站时间t后,我们可以查询t时刻前的树,查出当前点入栈之前的栈顶的信息,然后在答案线段树上和可持久化线段树上修改。
代码:
#include<iostream> #include<stdio.h> #include<string.h> #define N 500005 #define lson id*2 #define rson id*2+1 using namespace std; int n,m,sum[N*4],lazy[N*4]; void pd(int id,int l,int r,int mid) { if(lazy[id]==-1) return ; sum[lson]=(mid-l+1)*lazy[id]; sum[rson]=(r-mid)*lazy[id]; lazy[lson]=lazy[rson]=lazy[id]; lazy[id]=-1; } void add(int id,int L,int R,int l,int r,int v) { //cout<<L<<" "<<R<<" "<<l<<" "<<r<<endl; if(L>r||R<l) return ; if(L>=l&&R<=r) { lazy[id]=v; sum[id]=(R-L+1)*v; return ; } int mid=(L+R)>>1; pd(id,L,R,mid); add(lson,L,mid,l,r,v); add(rson,mid+1,R,l,r,v); sum[id]=sum[lson]+sum[rson]; } int getans(int id,int L,int R,int l,int r) { if(L>r||R<l) return 0; if(L>=l&&R<=r) return sum[id]; int mid=(L+R)>>1; pd(id,L,R,mid); int ret=getans(lson,L,mid,l,r)+getans(rson,mid+1,R,l,r); return ret; } int tim[N*75],val[N*75],tot,ls[N*75],rs[N*75]; int rt ; void down(int id) { if(tim[id]==-1) return; ++tot;tim[tot]=tim[id];ls[tot]=ls[ls[id]];rs[tot]=rs[ls[id]];ls[id]=tot;val[tot]=val[id]; ++tot;tim[tot]=tim[id];ls[tot]=ls[rs[id]];rs[tot]=rs[rs[id]];rs[id]=tot;val[tot]=val[id]; tim[id]=-1; } void build(int pre,int &now,int L,int R,int l,int r,int t,int v) { now=++tot; if(L>=l&&R<=r) { tim[now]=t; val[now]=v; return ; } //cout<<L<<" "<<R<<" "<<l<<" "<<r<<endl; if(pre) down(pre); ls[now]=ls[pre],rs[now]=rs[pre]; int mid=(L+R)>>1; if(mid>=l) build(ls[pre],ls[now],L,mid,l,r,t,v); if(mid+1<=r) build(rs[pre],rs[now],mid+1,R,l,r,t,v); } int get(int id,int l,int r,int pos) { if(!id||tim[id]!=-1) return id; int mid=(l+r)>>1; if(pos<=mid) return get(ls[id],l,mid,pos); return get(rs[id],mid+1,r,pos); } void del(int x,int y) { int id=get(rt[y-1],1,n,x); if(!id) { rt[y]=rt[y-1]; return ; } // if(tim[id]==0) while(1); id=get(rt[tim[id]-1],1,n,x); build(rt[y-1],rt[y],1,n,x,x,tim[id],val[id]); add(1,1,n,x,x,val[id]); } void change(int l,int r,int v,int i) { build(rt[i-1],rt[i],1,n,l,r,i,v); add(1,1,n,l,r,v); } int ty; int ans; int main() { scanf("%d%d%d",&n,&m,&ty); memset(lazy,-1,sizeof(lazy)); memset(tim,-1,sizeof(tim)); for(int i=1,aa,bb,cc,dd;i<=m;i++) { scanf("%d",&aa); if(aa==1) { scanf("%d%d",&bb,&cc); bb=(bb+ans*ty)%n+1; cc=(cc+ans*ty)%n+1; if(bb>cc) swap(bb,cc); ans=getans(1,1,n,bb,cc); printf("%d\n",ans); rt[i]=rt[i-1]; } else if(aa==2) { scanf("%d",&bb); bb=(bb+ans*ty)%n+1; del(bb,i); } else if(aa==3) { scanf("%d%d%d",&bb,&cc,&dd); bb=(bb+ans*ty)%n+1; cc=(cc+ans*ty)%n+1; if(bb>cc) swap(bb,cc); change(bb,cc,dd,i); } } }
相关文章推荐
- Struts拦截器学习笔记
- CodeForces 131C The World is a Theatre 组合数
- 稳定排序(sort+结构体)
- 【codevs 1225】八数码难题
- angular.js ui-route 可以实现路由嵌套
- linux namespace
- Keil uVision4库函数vsscanf()的bug以及解决
- 计数排序
- TCP序列号和确认号详解
- 转载自运维网和51CTO-AD中FSMO五大角色的介绍及操作
- bootstrap tab切换如何让鼠标移动自动切换内容
- 五子棋-b
- Spring AOP: Spring之面向方面编程
- Android 分享SDK的实现
- 关于handler
- android实现点击空白处,软键盘消失事件
- 小记——daemon进程
- 分析C语言一个简单程序
- MyBatis 多表联合查询及优化
- 精简的后台程序代码——Sql