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. Hotkeys.js 2.0.2 发布,JS 网页快捷键设置,捕获键盘输入和输入的组合键快捷键,它没有依赖

    这是一个强健的 Javascript 库用于捕获键盘输入和输入的组合键,它没有依赖,压缩只有只有(~3kb),gzip:1.9k. 更新内容: 添加测试用例: 添加更多特殊键支持: 修复bug. __ ...

  2. react 的虚拟dom

    前端优化的主要方面就是减少页面的DOM操作,减少重排和重绘,React在这方面做了优化,采用了所谓的虚拟DOM,其实我们平时也会遇到虚拟DOM,只是你没有注意罢了,请听我娓娓道来.  所谓的虚拟DOM ...

  3. SummerVocation_Learning--java的String类方法总结

    壹: public char charAt(int index),返回字符串中第index个字符. public int length(), 返回字符串长度. public int indexOf(S ...

  4. HDU-3366-Count the string(KMP,DP)

    Count the string Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...

  5. 精通SpringBoot--整合Redis实现缓存

    今天我们来讲讲怎么在spring boot 中整合redis 实现对数据库查询结果的缓存.首先第一步要做的就是在pom.xml文件添加spring-boot-starter-data-redis.要整 ...

  6. A * B Problem Plus HDU - 1402 (FFT)

    A * B Problem Plus HDU - 1402 (FFT) Calculate A * B.  InputEach line will contain two integers A and ...

  7. 动态规划:HDU1224-Free DIY Tour

       Free DIY Tour Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  8. Linux命令之---mv

    命令简介 mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files) 命令格式 mv [选项] 源文件或目录 目标文件或目录 命令参数 -b 若需覆盖文件,则覆 ...

  9. Kali 网络配置

    一.配置IP 编辑/etc/network/interfaces # This file describes the network interfaces available on your syst ...

  10. RF、GBDT、XGBOOST常见面试算法整理

    1.  RF(随机森林)与GBDT之间的区别 相同点: 1)都是由多棵树组成的 2)最终的结果都是由多棵树一起决定 不同点: 1)  组成随机森林的树可以是分类树也可以是回归树,而GBDT只由回归树组 ...