博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
题解 P1886 【滑动窗口】
阅读量:5086 次
发布时间:2019-06-13

本文共 3269 字,大约阅读时间需要 10 分钟。

线段树优化做法

如果仔细读过题的话,就会发现这是一个静态的区间查询最大值与最小值。

很多人(如果你学过线段树的话)就会想到,我当年学线段树的例题不就是区间加,然后求区间最大值吗?何况还没有区间加这一操作,岂不嗨皮哉???

好的,看看数据范围。

1*10^6???

线段树能过的去吗?还需要维护两个值,不得两棵线段树吗???

这个问题就不难解决了:

首先是时间的问题。我们的常识告诉我们,O(nlogn)只能走100000,但是如果你的常数不是很大的话,单从线段树的时间复杂度上说,nlog₂n在n=1000000的话是1000000*20=20000000,加点常数还是可以过的。

接下来解决很多人总要写两棵线段树的问题。由上文知,20000000要求你的常数很小,而你如果写两棵线段树会增大你的常数,而且写起来费事,所以不如只写一棵线段树。

怎么写呢???

在此之前先了解一下我的宏定义QAQ,方便理解以下代码

#define root 1,n,1          //根节点的左右边界与节点编号#define lson l,m,rt<<1      //左儿子的左右边界与节点编号#define rson m+1,r,rt<<1|1  //右儿子的左右边界与节点编号

我们不妨写一个结构体

struct node{    int maxx,minn;//最大值与最小值}t, z[mn<<2];//t是用来接query函数(一会再讲)的返回值的             //z[]是用来存线段树主体的。

直接一起存,是不是省了两棵线段树的麻烦?

那么怎么更新呢?分别更新呗:

inline void update(int rt){//rt表示要更新的线段树节点    z[rt].maxx=max(z[rt<<1].maxx,z[rt<<1|1].maxx);    z[rt].minn=min(z[rt<<1].minn,z[rt<<1|1].minn);}

这样就可以更新当前节点啦!

我们的基础数值可以和建树操作一起进行。

inline void build(intl,int r,int rt){//建树    if(l==r){z[rt].minn=z[rt].maxx=read();}//这里一起进行(我用了个读入优化)    int m=(l+r)>>1;    build(lson);//左儿子    build(rson);//右儿子    update(rt);}

因为我们没有区间值的变化,所以就不写modify这部分了。接下来是一个查询的过程,这里有个细节,你要同时返回最小值与最大值,不能把左边和右边的一组答案直接作为这一个区间的答案,所以你只能把左右两边同时比较最大值最小值,最大值取两者中最大值最大,最小值取两者中最小值最小,然后合并成一个node结构体。

所以,为了简化这一步骤,可以多写一个函数:

inline node cmp(node a,node b){//函数名字就不要深究了    return (node){a.maxx > b.maxx ? a.maxx : b.maxx, a.minn < b.minn ? a.minn : b.minn};}

然后用在查询(query)函数中:

这里有个小小的优化:

如果你的判断是只有两个的话,这样会多次进入循环,所以可以直接从判断上省去一部分时间。

inline node query(int l,int r,int rt,int nowl,int nowr){    //变量分别是线段树左右端点,线段树节点编号,查询范围左右端点    if(nowl<=l && r<=nowr){return z[rt];}    int m=(l+r)>>1;    if(nowl<=m){        if(m

这样返回的就是区间的最大值和最小值了

主函数的部分直接在完整代码中详细讲解了

代码:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;#define go(i, j, n, k) for (int i = j; i <= n; i += k)#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)#define mn 1000100#define inf 1 << 30#define ll long long#define ld long double#define fi first#define se second#define root 1, n, 1#define lson l, m, rt << 1#define rson m + 1, r, rt << 1 | 1#define bson l, r, rtinline int read(){ int f = 1, x = 0;char ch = getchar(); while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();} while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f;}inline void write(int x){ if (x < 0)putchar('-'),x = -x; if (x > 9)write(x / 10); putchar(x % 10 + '0');}//This is AC head above...struct node{ int maxx, minn;} t,z[mn<<2];inline node cmp(node a,node b){ return (node){a.maxx > b.maxx ? a.maxx : b.maxx, a.minn < b.minn ? a.minn : b.minn};}inline void update(int rt){ z[rt].maxx = max(z[rt << 1].maxx, z[rt << 1 | 1].maxx); z[rt].minn = min(z[rt << 1].minn, z[rt << 1 | 1].minn);}inline void build(int l,int r,int rt){ if(l==r){ z[rt].maxx = z[rt].minn = read(); return; } int m = (l + r) >> 1; build(lson); build(rson); update(rt);}inline node query(int l,int r,int rt,int nowl,int nowr){ if(nowl<=l && r<=nowr){ return z[rt]; } int m = (l + r) >> 1; if(nowl<=m){ if(m

第九次写题解,希望可以帮到用线段树却惨遭TLE的同学

转载于:https://www.cnblogs.com/yizimi/p/10056254.html

你可能感兴趣的文章
会计电算化常考题目一
查看>>
阿里云服务器CentOS6.9安装Mysql
查看>>
剑指offer系列6:数值的整数次方
查看>>
js 过滤敏感词
查看>>
poj2752 Seek the Name, Seek the Fame
查看>>
软件开发和软件测试,我该如何选择?(蜗牛学院)
查看>>
基本封装方法
查看>>
bcb ole拖拽功能的实现
查看>>
生活大爆炸之何为光速
查看>>
bzoj 2456: mode【瞎搞】
查看>>
[Typescript] Specify Exact Values with TypeScript’s Literal Types
查看>>
[GraphQL] Reuse Query Fields with GraphQL Fragments
查看>>
Illustrated C#学习笔记(一)
查看>>
理解oracle中连接和会话
查看>>
两种最常用的Sticky footer布局方式
查看>>
Scrapy实战篇(三)之爬取豆瓣电影短评
查看>>
HDU 5510 Bazinga KMP
查看>>
[13年迁移]Firefox下margin-top问题
查看>>
Zookeeper常用命令 (转)
查看>>
Java程序IP v6与IP v4的设置
查看>>