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. 【全面解禁!真正的Expression Blend实战开发技巧】第七章 MVVM初体验-在DataGrid行末添加按钮

    原文:[全面解禁!真正的Expression Blend实战开发技巧]第七章 MVVM初体验-在DataGrid行末添加按钮 博客更新较慢,先向各位读者说声抱歉.这一节讲解的依然是开发中经常遇到的一种 ...

  2. Ionic3开发环境搭建-VS Code

    原文:Ionic3开发环境搭建-VS Code 一.Ionic3在VS Code中的开发环境搭建 1.全局安装Ionic包 npm install -g cordova ionic 使用 ionic ...

  3. 操作XML文档遇到的XMLNS问题及解决方法 (C# 和 PHP)

    原文:操作XML文档遇到的XMLNS问题及解决方法 (C# 和 PHP) 不管是用 PHP 还是 C#, 在操作 XML 的时候我们除了一个节点一个节点去取值之外, 还有一个非常方便的表达式, 就是 ...

  4. GIS基础软件及操作(六)

    原文 GIS基础软件及操作(六) 练习六.空间分析的应用 1.加深对缓冲区分析基本原理.方法的认识:2.熟练掌握距离制图创建缓冲区技术方法.3.掌握利用缓冲区分析方法解决地学空间分析问题的能力. 1. ...

  5. 编译时MSIL注入--实践Mono Cecil(1)

    原文:编译时MSIL注入--实践Mono Cecil(1) 紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务—MSBuild Task(csproject),在第一 ...

  6. select ,update 加锁

    最近我在弄一个项目,其中涉及到了数据批量导入数据库的过程,在导入数据的时候,每一条数据会生成一个唯一标识,但是我发现有些数据的标识重复了.我在网上查了一下说这是“数据库 并发性”的问题解决方案,上锁. ...

  7. WCSTOMBS 函数不支持中文件的解决方法(设置代码页)

    代码页没有进行设置.需要调用locale.h 中定义的一个函数设置默认的代码页 _tsetlocale(LC_ALL,_T(""));//设置代码页  wcstombs(sendB ...

  8. JPA 报错解决方案 com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert explicit value for identity column in table 'test_db' when IDENTITY_INSERT is set to OFF.

    这种错误插入数据时就是hibernate的自增长字段生成规则应该用native 在字段前加入注解 @GeneratedValue(generator="generator") @G ...

  9. C语言实现常用查找算法——二分查找

    #include<stdio.h> void insert_sort(int a[],int n); int binary_search(int a[],int x,int n); voi ...

  10. vue的checkbox或多选的select的代码例子

    另外一种实现checkbox的vue绑定方法代码: 给v-model绑定一个相同的数组类型的属性: <div id="app"> <label>jack&l ...