cogs 2320. [HZOI 2015]聪聪的世界题解
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]聪聪的世界题解的更多相关文章
- COGS 2580. [HZOI 2015]偏序 II
COGS 2580. [HZOI 2015]偏序 II 题目传送门 题目大意:给n个元素,每个元素有具有4个属性a,b,c,d,求i<j并且ai<aj,bi<bj,ci<cj, ...
- cogs 2123. [HZOI 2015] Glass Beads
2123. [HZOI 2015] Glass Beads ★★★ 输入文件:MinRepresentations.in 输出文件:MinRepresentations.out 简单对比时 ...
- COGS 2188. [HZOI 2015] Math 题解
题目描述: 给定n个数X1-Xn,求下面式子的值(整数部分): n<=107,xi<=109且互不相同. 分析: 其实一开始看见这道题我也吓傻了,k这么大,再说我又是数论鶸渣,打死也不 ...
- [COGS 2287][HZOI 2015]疯狂的机器人
Description 题库链接 现在在二维平面内原点上有一只机器人,他每次可以选择向右走,向左走,向下走,向上走和不走(每次如果走只能走一格).机器人不能走到横坐标是负数或者纵坐标是负数的点上. 给 ...
- [COGS 2258][HZOI 2015]复仇的序幕曲
Description 你还梦不梦痛不痛,回忆这么重你怎么背得动 ----序言 当年的战火硝烟已经渐渐远去,可仇恨却在阿凯蒂王子的心中越来越深 他的叔父三年前谋权篡位,逼宫杀死了他的父王,用铁血手腕平 ...
- cogs 2355. [HZOI 2015] 有标号的DAG计数 II
题目分析 来自2013年王迪的论文<浅谈容斥原理> 设\(f_{n,S}\)表示n个节点,入度为0的点集恰好为S的方案数. 设\(g_{n,S}\)表示n个节点,入度为0的点集至少为S的方 ...
- COGS 2280. [HZOI 2015]树白黑
★★ 输入文件:B_Tree.in 输出文件:B_Tree.out 简单对比时间限制:2 s 内存限制:512 MB [题目描述] 给定一棵有根树,树根为1,一开始这棵树所有节点均为白 ...
- COGS 2294. [HZOI 2015] 释迦
额,其实就是裸的三模数NTT,上一篇已经说过了 哦,还有一个就是对乘起来炸long long的数取模,用long double之类的搞一下就好,精度什么的,,(看出题人心情??) #include&l ...
- 【COGS】2287:[HZOI 2015]疯狂的机器人 FFT+卡特兰数+排列组合
[题意][COGS 2287][HZOI 2015]疯狂的机器人 [算法]FFT+卡特兰数+排列组合 [题解]先考虑一维的情况,支持+1和-1,前缀和不能为负数,就是卡特兰数的形式. 设C(n)表示第 ...
随机推荐
- datacontract helper
public static class DataContractHelper { public static void ToDCFile<T>(this T obj, string pat ...
- 【Python】Camera拍照休眠唤醒测试
#!/usr/bin/python # -*- coding: UTF-8 -*- import os import sys import time rebootCount = int(input(& ...
- Win8Metro(C#)数字图像处理--2.32图像曝光算法
原文:Win8Metro(C#)数字图像处理--2.32图像曝光算法 [函数名称] 图像曝光函数ExposureProcess(WriteableBitmap src,int exposureV ...
- SQL 修改主键约束
原文:SQL 修改主键约束 今天在学习数据库的时候遇到一个关于如何修改主键约束的问题,抄录下来以供备用. --修改主键约束用SQL --获取主键约束名字 declare @csname varchar ...
- Windows10 【系统周期表】【系统下载表】【大型软件表】
系统周期表 商用名称 商用英文名 代号 版本 系统版本 上市日期 服务周期 备注 Windows 10 无 Threshold 1 1507 10.0.10240.17443 2015.07.29 2 ...
- Visual studio 创建通用项目失败vstemplate
Visual studio 创建项目失败 提示 the vstemplate file references the wizard class 'Microsoft.VisualStudio.WinR ...
- LINQ学习笔记(二)
上一篇是根据百度百科写的随便,同时也纠正我对LINQ的看法,因为首次接触LINQ是使用EF对数据库数据的操作. 所以误以为它操作数据库的一种新手段. LINQ语言集成查询是一组技术的名称,这些技术建立 ...
- Qt https 用户认证authenticationRequired()
用QNetworkAccessManager以POST方式访问https需要用户认证,所以用SIGNAL(authenticationRequired(QNetworkReply *, QAuthen ...
- MySQL InnoDB缓冲池(Buffer Pool)
InnoDB缓冲池并不仅仅缓存索引,它还会缓存行的数据.自适应哈希索引.插入缓冲(Insert Buffer).锁,以及其他内部数据结构. InnoDB还使用缓冲池来帮助延迟写入,这样就能合并多个写入 ...
- 12 寸 Retina MacBook 的大秘密: 可用移动电源充电
苹果新款12寸Retina MacBook虽然只有一个USB-C接口,但这个接口的能力却十分强大.它不仅可以进行数据传输和视频输出,还能接收和输入电源.这也就是说,你可以使用移动电源对其进行充电,如果 ...