2320. [HZOI 2015]聪聪的世界

时间限制:6 s   内存限制:512 MB

【题目描述】

背景:

聪聪的性取向有问题。

题目描述:

聪聪遇到了一个难题:

给出一个序列a1…an,完成以下操作:

1  x 询问从x向左数第一个<ax的数;

2  x 询问从x向左数第一个>ax的数;

3  x 询问从x向右数第一个<ax的数;

4  x 询问从x向右数第一个>ax的数;

5  x y 交换ax与ay;

6  x y w 给ax…ay加上w;

7  x y w 给ax…ay减去w。

聪聪急切的想知道答案,因为他完成任务后就可以迎娶高富帅,出任CEO,走上人生巅峰,成为人生赢家!

请你帮帮他。

【输入格式】

第一行 n,m。

第二行 a1…an。

第三行到m+2行为以上七个操作。

【输出格式】

对于每个op>=1且op<=4输出一行表示答案,无解输出-1。

【样例输入】

5 5

8 2 0 0 9

1 2

5 1 3

7 1 3 1

4 2

1 1

【样例输出】

-1

7

-1

【提示】

10%  n,m<=10000

40%  n,m<=100000

100%  n,m<=1000000

对于所有输入的数保证在[0,10^9]范围内

  学长们出的题造的孽啊,貌似打法很多,我在这里只讲一下线段树解法。

  首先先膜拜一下     神利·代目   stdafx.h,两位学长,我是在他们的引导下想出的O(log)时间复杂度内完成前4个操作的。

  因为这四个操作本质一样,因此我们就只讲第一种操作。

  请读者自己先思考5~10分钟,看看能否相出log复杂度的前四种操作打法,提醒一下,从根节点边向下边二分不靠谱。

  开讲了,首先,线段树是一棵完全二叉树,因此它满足一个规律,兄弟节点的编号亦或1就是他自己,而它自己的编号/2就是他父亲的编号,因此我们完全可以用这个性质从下向上攀爬,再利用这个性质从上向下攀爬。

 #include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
long long n,m;
struct no{
long long left,right;
long long mid,mn;
long long mx,lazy;
}node[];
long long a[];
long long dl[];
void build(long long left,long long right,long long x){
node[x].left=left;
node[x].right=right;
if(left==right)
{
dl[left]=x;
node[x].mn=node[x].mx=a[left];
return;
}
long long mid=(left+right)/;
node[x].mid=mid;
build(left,mid,*x);
build(mid+,right,*x+);
node[x].mx=max(node[*x].mx,node[*x+].mx);
node[x].mn=min(node[x*].mn,node[*x+].mn);
}
void pushdown(long long x){
if(node[x].lazy)
{
node[*x].lazy+=node[x].lazy;
node[*x+].lazy+=node[x].lazy;
node[*x].mx+=node[x].lazy;
node[*x+].mx+=node[x].lazy;
node[x*].mn+=node[x].lazy;
node[*x+].mn+=node[x].lazy;
node[x].lazy=;
}
}
long long get(long long left,long long right,long long x){
if(node[x].left==node[x].right)
{
return node[x].mx;
}
pushdown(x);
long long mid=node[x].mid;
if(right<=node[x].mid)
return get(left,right,*x);
else
return get(left,right,*x+);
}
void change(long long left,long long right,long long x,long long z){
if(node[x].left==node[x].right)
{
node[x].mn=z;
node[x].mx=z;
return;
}
pushdown(x);
long long mid=node[x].mid;
if(right<=node[x].mid)
change(left,right,*x,z);
else
change(left,right,*x+,z);
node[x].mx=max(node[*x].mx,node[*x+].mx);
node[x].mn=min(node[*x].mn,node[+*x].mn);
}
void add(long long left,long long right,long long x,long long z){
if(node[x].left==left&&node[x].right==right)
{
node[x].mx+=z;
node[x].mn+=z;
node[x].lazy+=z;
return;
}
pushdown(x);
long long mid=node[x].mid;
if(right<=mid)
add(left,right,*x,z);
else if(left>mid)
add(left,right,*x+,z);
else
add(left,mid,*x,z),add(mid+,right,*x+,z);
node[x].mx=max(node[*x].mx,node[*x+].mx);
node[x].mn=min(node[x*].mn,node[*x+].mn);
}
long long que_ls(long long x,long long z,long long buf){
if(node[x].left==node[x].right)
return node[x].left;
if(node[*x+].mn+buf+node[x].lazy<z)
return que_ls(*x+,z,buf+node[x].lazy);
else
return que_ls(*x,z,buf+node[x].lazy);
}
long long get_ls(long long x,long long z){
if(x==)
return -;
if(!(x%))
return get_ls(x/,z+node[x].lazy);
else
{
if(z+node[x].lazy>node[x^].mn)
return que_ls(x^,z+node[x].lazy,);
else
return get_ls(x/,z+node[x].lazy);
}
}
long long que_lb(long long x,long long z,long long buf){
if(node[x].left==node[x].right)
return node[x].left;
if(node[*x+].mx+buf+node[x].lazy>z)
return que_lb(x*+,z,buf+node[x].lazy);
else
return que_lb(x*,z,buf+node[x].lazy);
}
long long get_lb(long long x,long long z){
if(x==)
return -;
if(!(x%))
return get_lb(x/,z+node[x].lazy);
else
{
if(z+node[x].lazy<node[x^].mx)
return que_lb(x^,z+node[x].lazy,);
else
return get_lb(x/,z+node[x].lazy);
}
}
long long que_rs(long long x,long long z,long long buf){
if(node[x].left==node[x].right)
return node[x].left;
if(node[*x].mn+buf+node[x].lazy<z)
return que_rs(x*,z,buf+node[x].lazy);
else
return que_rs(x*+,z,buf+node[x].lazy);
}
long long get_rs(long long x,long long z){
if(x==)
return -;
if(x%)
return get_rs(x/,z+node[x].lazy);
else
{
if(z+node[x].lazy>node[x^].mn)
return que_rs(x^,z+node[x].lazy,);
else
return get_rs(x/,z+node[x].lazy);
}
}
long long que_rb(long long x,long long z,long long buf){
if(node[x].left==node[x].right)
return node[x].left;
if(node[x*].mx+buf+node[x].lazy>z)
return que_rb(x*,z,buf+node[x].lazy);
else
return que_rb(x*+,z,buf+node[x].lazy);
}
long long get_rb(long long x,long long z){
if(x==)
return -;
if(x%)
return get_rb(x/,z+node[x].lazy);
else
{
if(z+node[x].lazy<node[x^].mx)
return que_rb(x^,z+node[x].lazy,);
else
return get_rb(x/,z+node[x].lazy);
}
}
int main(){
freopen("ccsworld.in","r",stdin);
freopen("ccsworld.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=;i<=n;i++)
scanf("%lld",&a[i]);
build(,n,);
for(int i=;i<=m;i++)
{
long long tt;
scanf("%lld",&tt);
if(tt==)
{
long long x;
scanf("%lld",&x);
long long y=get_ls(dl[x],node[dl[x]].mx-node[dl[x]].lazy);
if(y!=-) printf("%lld\n",get(y,y,));
else printf("%lld\n",y);
}
if(tt==)
{
long long x;
scanf("%lld",&x);
long long y=get_lb(dl[x],node[dl[x]].mx-node[dl[x]].lazy);
if(y!=-) printf("%lld\n",get(y,y,));
else printf("%lld\n",y);
}
if(tt==)
{
long long x;
scanf("%lld",&x);
long long y=get_rs(dl[x],node[dl[x]].mx-node[dl[x]].lazy);
if(y!=-) printf("%lld\n",get(y,y,));
else printf("%lld\n",y);
}
if(tt==)
{
long long x;
scanf("%lld",&x);
long long y=get_rb(dl[x],node[dl[x]].mx-node[dl[x]].lazy);
if(y!=-) printf("%lld\n",get(y,y,));
else printf("%lld\n",y);
}
if(tt==)
{
long long x,y;
scanf("%lld%lld",&x,&y);
long long xx,yy;
xx=get(x,x,);
yy=get(y,y,);
change(x,x,,yy);
change(y,y,,xx);
}
if(tt==)
{
long long x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
add(x,y,,z);
}
if(tt==)
{
long long x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
add(x,y,,-z);
}
}
//while(1);
return ;
}

一份长达5k的代码,慎入

  因此,我们大可开个数组存下每个叶节点的编号,便于查找,然后就从我们询问的叶节点向上查找,如果当前位置为右子树,那么就看一下他的兄弟的最小值是否比它小,如果不是,那么继续向上爬,如果是,我们就从他的兄弟节点向下爬。如果当前位置是左子树,我们就得接着向上爬了,他的右子树是不满足条件的,因为本题有区间操作,所以lazy数组就成了一个让人头痛的东西,让我们来慢慢分析。

  首先我向上爬时路径上的lazy是影响的,因为我们都是从叶节点向上爬,因此叶节点的数值是最晚更新的,因此向上爬的lazy是一定要加上的,那么有人可能回去问了,有可能之前还有区间操作只是没下放呢,这就不必担心了,因为如果他没得到lazy,他的兄弟一定也没得到,两者抵消。

  其次,向下爬的lazy也是会影响的,因为我们要的是最靠近x的叶节点,因此我们应采用先右后左的方法,如果右子树的最小值比上面那步传下来的参数小,就搜右子树,左子树就不必管了,而lazy也是需要一直跟着下放,原理见上。

  我们最终传回来的值并不是当前节点的值,因为上面的值可能还没传下来,因此我们传的应当是它的位置,再从根节点向下搞也就是单点查询了。

  至于其他三个操作,请读者自己思考并实现。

  打完代码后提交,全WA,被QTY2001神犇提醒,没开long long。交完就A了,没啥坑点,主要是码力,被教练员吐槽代码能力弱的我都能在一小时之内搞掉,这道题的难度也是没谁了。这或许就是他只有3星的原因吧。

cogs 2320. [HZOI 2015]聪聪的世界题解的更多相关文章

  1. COGS 2580. [HZOI 2015]偏序 II

    COGS 2580. [HZOI 2015]偏序 II 题目传送门 题目大意:给n个元素,每个元素有具有4个属性a,b,c,d,求i<j并且ai<aj,bi<bj,ci<cj, ...

  2. cogs 2123. [HZOI 2015] Glass Beads

    2123. [HZOI 2015] Glass Beads ★★★   输入文件:MinRepresentations.in   输出文件:MinRepresentations.out   简单对比时 ...

  3. COGS 2188. [HZOI 2015] Math 题解

      题目描述: 给定n个数X1-Xn,求下面式子的值(整数部分): n<=107,xi<=109且互不相同. 分析: 其实一开始看见这道题我也吓傻了,k这么大,再说我又是数论鶸渣,打死也不 ...

  4. [COGS 2287][HZOI 2015]疯狂的机器人

    Description 题库链接 现在在二维平面内原点上有一只机器人,他每次可以选择向右走,向左走,向下走,向上走和不走(每次如果走只能走一格).机器人不能走到横坐标是负数或者纵坐标是负数的点上. 给 ...

  5. [COGS 2258][HZOI 2015]复仇的序幕曲

    Description 你还梦不梦痛不痛,回忆这么重你怎么背得动 ----序言 当年的战火硝烟已经渐渐远去,可仇恨却在阿凯蒂王子的心中越来越深 他的叔父三年前谋权篡位,逼宫杀死了他的父王,用铁血手腕平 ...

  6. cogs 2355. [HZOI 2015] 有标号的DAG计数 II

    题目分析 来自2013年王迪的论文<浅谈容斥原理> 设\(f_{n,S}\)表示n个节点,入度为0的点集恰好为S的方案数. 设\(g_{n,S}\)表示n个节点,入度为0的点集至少为S的方 ...

  7. COGS 2280. [HZOI 2015]树白黑

    ★★   输入文件:B_Tree.in   输出文件:B_Tree.out   简单对比时间限制:2 s   内存限制:512 MB [题目描述] 给定一棵有根树,树根为1,一开始这棵树所有节点均为白 ...

  8. COGS 2294. [HZOI 2015] 释迦

    额,其实就是裸的三模数NTT,上一篇已经说过了 哦,还有一个就是对乘起来炸long long的数取模,用long double之类的搞一下就好,精度什么的,,(看出题人心情??) #include&l ...

  9. 【COGS】2287:[HZOI 2015]疯狂的机器人 FFT+卡特兰数+排列组合

    [题意][COGS 2287][HZOI 2015]疯狂的机器人 [算法]FFT+卡特兰数+排列组合 [题解]先考虑一维的情况,支持+1和-1,前缀和不能为负数,就是卡特兰数的形式. 设C(n)表示第 ...

随机推荐

  1. 怎么给开源项目提PR?

    1. fork 你要的项目 2. 下载到本地 相关步骤如下 在你需要的文件夹下面,右键 git bash 命令,打开 git 命令框 执行如下指令可将项目代码下载到当前目录 ~~~ git clone ...

  2. LOCK_TIMEOUT

    SET LOCK_TIMEOUT 1000 begin tran TranNameA select * from tablenameA WITH (updlock) where... waitfor  ...

  3. PostgreSQL在win7上安装详细步骤

    原文:PostgreSQL在win7上安装详细步骤 PostgreSQL安装: 一.windows下安装过程 安装介质:postgresql-9.1.3-1-windows.exe(46M),安装过程 ...

  4. 正则表达式-Csharp

    原文:正则表达式-Csharp 学习笔记:正则表达式 一. 正则表达式 正则表达式(Regex)是用来进行文本处理的技术,是语言无关的,在几乎所有语言中都有实现. 一个正则表达式就是由普通的字符及特殊 ...

  5. Android零基础入门第59节:AnalogClock、DigitalClock和TextClock时钟组件

    原文:Android零基础入门第59节:AnalogClock.DigitalClock和TextClock时钟组件 在前面一期,我们学习了DatePicker和TimePicker,在实际开发中其不 ...

  6. 百度网盘背后的存储系统atlas

    原文  http://www.bitstech.net/2015/07/25/baidu-atlas/   百度网盘免费提供2TB存储, 它的存储量一定是惊人的, 支持它的存储系统atlas也是相当不 ...

  7. MongoDB自学日记1——基本操作

    作为一个做底层及后台研发的,最近对NoSQL却产生了浓厚的兴趣,加入了一个DBA群,据说北京排的上号的DBA都在里面,然而里面基本都是Oracle系的,MySQL和MongoDB系的少之又少.学习靠不 ...

  8. JVM检测&工具

    前几篇篇文章介绍了介绍了JVM的参数设置并给出了一些生产环境的JVM参数配置参考方案.正如之前文章中提到的JVM参数的设置需要根据应用的特性来进行设置,每个参数的设置都需要对JVM进行长时间的监测,并 ...

  9. 查看oracle/mysql数据库版本号

    1.1.       ORACLE 软件版本 使用oracle用户登录,输入echo "select * from v\$version;"|sqlplus -S / as sys ...

  10. 移动IM开发指南1:如何进行技术选型

    <移动IM开发指南>系列文章将会介绍一个IM APP的方方面面,包括技术选型.登陆优化等.此外,本文作者会结合他在网易云信多年iOS IM SDK开发的经验,深度分析实际开发中的各种常见问 ...