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)表示第 ...
随机推荐
- wpf自定义带刻度的柱状图控件
效果图: 主要代码xaml: <UserControl x:Class="INSControls._01Conning.Steer.ConningSpeedBar" xmln ...
- select ,update 加锁
最近我在弄一个项目,其中涉及到了数据批量导入数据库的过程,在导入数据的时候,每一条数据会生成一个唯一标识,但是我发现有些数据的标识重复了.我在网上查了一下说这是“数据库 并发性”的问题解决方案,上锁. ...
- MFC OnPaint()函数中最先调用CDialog::OnPaint()和最后调用CDialog::OnPaint()的巨大区别
OnPaint()函数中最先调用CDialog::OnPaint()和最后调用CDialog::OnPaint()的巨大区别,如果没有注意这个问题就会出现无厘头式的绘图问题-- 效果就是出不来!在经过 ...
- GetLastError()返回值列表(3259个错误列表)
GetLastError()返回值列表: [0]-操作成功完成. [1]-功能错误. [2]-系统找不到指定的文件. [3]-系统找不到指定的路径. [4]-系统无法打开文件. [5]-拒绝访问. [ ...
- CSocket实现端口扫描
界面如下: 主要代码如下: //对于每一个线程,传过去的参数 typedef struct ThreadParamStruct { CString strIP; //要扫描的IP地址 UINT uPo ...
- java多线程之线程安全
线程安全和非线程安全是多线程的经典问题,非线程安全会在多个线程对同一个对象并发访问时发生. 注意1: 非线程安全的问题存在于实例变量中,如果是方法内部的私有变量,则不存在非线程安全问题. 实例变量是对 ...
- 开源|性能优化利器:数据库审核平台Themis的选型与实践
作者:韩锋 出处:DBAplus社群分享:来源:宜信技术学院 Themis开源地址:https://github.com/CreditEaseDBA 一.面临的挑战 1.运维规模及种类 我相信,这也是 ...
- Nginx学习笔记---服务与集群
一.集群 什么是集群 服务器架构集群:多台服务器组成的响应式大并发,高数据量访问的架构体系. 特点: (1)成本高 (2)能够降低单台服务器的压力,使用流量平均分配到多台服务器 (3)使网站服务架构更 ...
- Tido 习题-二叉树-树状数组实现
题目描述 这就是一个简单的树状数组入门题 可以动态地进行区间和查询 随时可能会进行更新 #include<iostream> #include<cstdio> #inclu ...
- PDF Expert for Mac v2.4.22 中文破解版下载 PDF阅读编辑软件
PDF Expert for Mac v2.4.22 中文破解版下载:http://h5ip.cn/CsRN PDF Expert for Mac, iOS 上最好用的 PDF 编辑器之一,现在终于打 ...