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. 【Python】wifi开关测试

    #!/usr/bin/python # -*- coding: UTF-8 -*- import os import time def find_device(): os.system('adb ki ...

  2. Win8 Metro(C#)数字图像处理--2.62图像对数增强

    原文:Win8 Metro(C#)数字图像处理--2.62图像对数增强  [函数名称]   对数增强      WriteableBitmap LogenhanceProcess(Writeabl ...

  3. Oracle 存储过程创建及调用

    --------创建存储过程------- create or replace procedure TestSPas begin update table_name set CREATE_TIMEST ...

  4. 使用Visual Studio开发Python

    Python优秀的集成开发环境有PyCharm,Visual Studio Code等,当然你仍然可以使用Visual Studio进行开发.如果你熟悉Visual Studio,使用Visual S ...

  5. Virtualbox使用点滴(共享USB设备,Linux下我的用户没有加到vboxuser中去)

    由于网银客户端的问题,只能够在windows环境下支付,所以一直保存着一个激活的virtualbox下的windows,用来完成在线支付. 过去这个激活的windows是安装在ubuntu 10.10 ...

  6. c# 停靠窗体

    public partial class FrmAnchor : Form, IMessageFilter { public FrmAnchor(Control parentControlc, Con ...

  7. How Qt Signals and Slots Work(感觉是通过Meta根据名字来调用)

    Qt is well known for its signals and slots mechanism. But how does it work? In this blog post, we wi ...

  8. 条款17:以独立语句将newed对象置入智能指针

    请牢记: 以独立语句将newed对象存储于(置入)智能指针内.如果不这样做,一旦异常被跑出来,有可能导致难以察觉的资源泄露. 假设有个函数用来处理程序的优先权,另一个函数用来在某动态分配所得的Widg ...

  9. Java 诞生的趣事

    ​ Java 命名的由来 Java是印度尼西亚爪哇岛的英文名称,因盛产咖啡而闻名.Java语言中的许多库类名称,多与咖啡有关:如JavaBeans(咖啡豆).NetBeans(网络豆)以及Object ...

  10. 一次信号量引发的tomcat异常退出

    近期在玩大数据.有个朋友找过来,说他线上的tomcat会莫名其妙的退出,表示非常苦恼,请我帮看看.每次他发现退出了,都通过腾讯云的WEB控制台登录,启动tomcat. 本着助人为乐(shao kao ...