Description

有一个沙漏由两个上下相通玻璃球 \(A\) 和 \(B\) 构成,这两个玻璃球都含有一定量的沙子,我们暂且假定 \(AB\) 中位于上方的玻璃球的为 \(U\),下方的玻璃球为 \(L\),则除非 \(U\) 中没有沙子,否则每秒钟都会有1克沙子从 \(U\) 掉入 \(L\)。

在第 \(0\) 个时刻,\(A\) 中有 \(a\) 克沙子,\(B\) 中有 \(X−a\) 克沙子(总共有 \(X\) 克沙子),且 \(U\) 为 \(A\),\(L\) 为 \(B\) (即 \(A\) 上 \(B\) 下)。

在 \(r1,r2,...,rK\) 这些时刻,我们将倒转整个沙漏,使得原来的 \(U\) 变成 \(L\),原来的 \(L\) 变成 \(U\)。对于翻转操作,t时刻是指从第 \(0\) 个时刻起经过 \(t\) 秒后的时刻,我们可以将翻转沙漏的操作看做瞬间完成的。

现在有 \(Q\) 次询问,每一次询问会给定一对非负整数(\(t_i\),\(a_i\)),求 \(a=a_i\),第 \(t_i\) 时刻,\(A\) 中所含沙子的克数。

Input

第一行一个正整数X

第二行一个正整数K

第三行K个整数,表示r1,r2,...,rK

接下来一行一个正整数Q

接下来Q行,每行两个非负整数,分别表示每次次询问的(ti,ai)

Output

一共Q行

对于每次询问,输出一行一个非负整数表示答案。

题解:

神题啊!

这题可以用线段树做,我们维护 1~X 中,每个 a 经过一系列操作后的值,我们只用求每个询问中的 a,为了避免爆空间,我们动态开点。

我们把询问按时间排序,同时操作 r 数组,如果A再上面就减区间长度,和0取max,不然就加,与X取min。

像这样:

for(int i=0,j=1,rev=0;i<=n;i++,rev^=1){
while(j<=m&&q[j].t<=r[i+1]){
int tmp=query(root,1,X+1,q[j].a);
if(rev)tmp=min(X,tmp+q[j].t-r[i]);
else tmp=max(0,tmp-q[j].t+r[i]);
ans[q[j++].id]=tmp;
}
if(j>m)break;
int tmp=r[i+1]-r[i];
if(rev)Add(root,1,X+1,tmp);
else Sub(root,1,X+1,tmp);
}

然后每个线段树节点维护当前区间的最小值和最大值。

加的话,这样:

if(minv[o]>=X-x)
maxv[o]=minv[o]=set[o]=X,add[o]=0;
else if(maxv[o]<=X-x)
maxv[o]+=x,minv[o]+=x,add[o]+=x;

减就这样:

if(maxv[o]<=x)
maxv[o]=minv[o]=add[o]=set[o]=0;
else if(minv[o]>=x)
maxv[o]-=x,minv[o]-=x,add[o]-=x;

思路还是很简单的,这题主要还是码码。

COMPLETE CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std; int n,m,X,tot=0,root,r[100005];
int lch[8000005],rch[8000005];
int minv[8000005],maxv[8000005];
int set[8000005],add[8000005];
struct Question{
int t,a,id;
}q[100005];
int ans[100005]; bool comp(Question a,Question b){return a.t<b.t;} int newnode(int &o,int x,int y){
o=++tot,minv[o]=x,maxv[o]=y,set[o]=-1;
} void pushup(int o){
minv[o]=min(minv[lch[o]],minv[rch[o]]);
maxv[o]=max(maxv[lch[o]],maxv[rch[o]]);
} void pushdown(int o,int l,int r){
int mid=l+r>>1;
int &lc=lch[o],&rc=rch[o];
if(!lc)newnode(lc,l,mid-1);
if(!rc)newnode(rc,mid,r-1);
if(~set[o]){
minv[lc]=maxv[lc]=set[lc]=set[o];
minv[rc]=maxv[rc]=set[rc]=set[o];
add[lc]=add[rc]=0,set[o]=-1;
}
if(add[o]){
minv[lc]+=add[o],maxv[lc]+=add[o],add[lc]+=add[o];
minv[rc]+=add[o],maxv[rc]+=add[o],add[rc]+=add[o];
add[o]=0;
}
} void Sub(int &o,int l,int r,int x){
if(o==0)newnode(o,l,r-1);
if(maxv[o]<=x)
maxv[o]=minv[o]=add[o]=set[o]=0;
else if(minv[o]>=x)
maxv[o]-=x,minv[o]-=x,add[o]-=x;
else{
pushdown(o,l,r);
int mid=l+r>>1;
Sub(lch[o],l,mid,x),Sub(rch[o],mid,r,x);
pushup(o);
}
} void Add(int &o,int l,int r,int x){
if(o==0)newnode(o,l,r-1);
if(minv[o]>=X-x)
maxv[o]=minv[o]=set[o]=X,add[o]=0;
else if(maxv[o]<=X-x)
maxv[o]+=x,minv[o]+=x,add[o]+=x;
else{
pushdown(o,l,r);
int mid=l+r>>1;
Add(lch[o],l,mid,x),Add(rch[o],mid,r,x);
pushup(o);
}
} int query(int o,int l,int r,int x){
if(o==0)newnode(o,l,r-1);
if(r-l==1)return minv[o];
pushdown(o,l,r);
int mid=l+r>>1;
if(x<mid)return query(lch[o],l,mid,x);
else return query(rch[o],mid,r,x);
} int main(){
scanf("%d%d",&X,&n);
for(int i=1;i<=n;i++)scanf("%d",r+i);
r[n+1]=1e9;
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].t,&q[i].a);
q[i].id=i;
}
sort(q+1,q+m+1,comp);
for(int i=0,j=1,rev=0;i<=n;i++,rev^=1){
while(j<=m&&q[j].t<=r[i+1]){
int tmp=query(root,1,X+1,q[j].a);
if(rev)tmp=min(X,tmp+q[j].t-r[i]);
else tmp=max(0,tmp-q[j].t+r[i]);
ans[q[j++].id]=tmp;
}
if(j>m)break;
int tmp=r[i+1]-r[i];
if(rev)Add(root,1,X+1,tmp);
else Sub(root,1,X+1,tmp);
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}

[ARC082F] Sandglass(线段树)的更多相关文章

  1. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  2. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  3. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  4. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  5. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

  6. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

  7. CF719E(线段树+矩阵快速幂)

    题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作 分析:线段树 线段树的每个节点表示(f[i],f[i-1])这 ...

  8. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

  9. 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

随机推荐

  1. C++ 容器与继承

    如果容器类型定义为基类类型,那么虽然可以把派生类装进容器中,但是不能通过容器访问派生类自己的public成员,派生类将会倍切掉,只保留派生类的基类部分: 如果把容器定义为派生类类型,那么不能把基类类型 ...

  2. flask-bootstrap

    pip install bootstarp 使用bower安装bootstrap的命令是: bash$ bower install bootstrap不过问题出在如何安装bower上. 官方网站上这样 ...

  3. 第六篇:python中numpy.zeros(np.zeros)的使用方法

    用法:zeros(shape, dtype=float, order='C') 返回:返回来一个给定形状和类型的用0填充的数组: 参数:shape:形状 dtype:数据类型,可选参数,默认numpy ...

  4. mysql索引详细描述与应用场景

    索引的数据结构: (1)一般是B+tree:MySql使用最频繁的一个索引数据结构,数据结构以平衡树的形式来组织,因为是树型结构,所以更适合用来处理排序,范围查找等功能. (2)Hash:Hsah索引 ...

  5. JZOJ 5793. 【NOIP2008模拟】小S练跑步

    5793. [NOIP2008模拟]小S练跑步 (File IO): input:run.in output:run.out Time Limits: 2000 ms  Memory Limits:  ...

  6. Android中级教程之Android应用程序的生命周期

    Android应用程序的生命周期图 在大部分情况下,每个Android应用都将运行在自己的Linux进程中.当这个应用的某些代码需要执行时,进程就会被创建,并且将保持运行,直到该进程不再需要,而系统需 ...

  7. Django runserver支持https

    创建自签名ssl证书 1.下载软件openssl-0.9.8k_WIN32 2.解压后进入bin目录,双击打开openssl.exe,依次运行如下命令 genrsa -des3 -out server ...

  8. Python9-前端基础知识-day47

    web开发本质: 1.浏览器输入网址回车都发生了什么? 1.浏览器给服务端发送一个消息 2.服务端拿到消息 3.服务端返回消息 4.浏览器展示页面C/S架构----B/S架构客户端和服务端 消息的格式 ...

  9. 【转载】2015年8月编程语言排行榜:Java遥遥领先

    Java以4.5%的差距遥遥领先于第二名,回顾以前Java有这样的成绩还是在2008年.Java version 8的成功主要是因为函数式编程习语的添加.Java出现下滑是在2010年 Oracle收 ...

  10. as API一些容易忘记的属性和方法

    1.在flash动画里的一些动态文本会随着动画的执行,有抖动,解决问题的方法: tt为动画里的动态文本,tt.transform.matrix=null;