首页 > 其他分享 >P8618 [蓝桥杯 2014 国 B] Log 大侠

P8618 [蓝桥杯 2014 国 B] Log 大侠

时间:2022-11-04 22:25:25浏览次数:61  
标签:qr log 标记 int 线段 P8618 蓝桥 区间 2014

简要题意

给你一个长度为 \(n\) 的正整数序列 \(a\),有 \(m\) 个询问,每一个询问给出一个区间 \([l,r]\)。定义函数 \(f(x)=\lfloor\log_{2}(x)+1\rfloor\)。将 \([l,r]\) 的所有元素 \(a_p\) 修改为 \(f(a_p)\)。然后输出序列 \(a\) 的全局和。

对于 \(100\%\) 的数据,\(1 \leq n,m \le 10^5,1 \leq a_i \leq 10^9\)。

思路

前置知识:线段树。

这一道题是无标记区间修改线段树(我自己取得名字)的模板题。

这道题如果使用普通的线段树区间修改(打标记法),无论是标记下传还是标记永久化,都有一个问题:如何实现区间更新?也就是说知道 \(\sum_{i=l}^{r}{a_i}\),如何求 \(\sum_{i=l}^{r}{f(a_i)}\)?

这不是不好求,是不能求。

那我们考虑回归暴力。暴力思路很简单,在线段树上找到 \([l,r]\) 的所有元素,一一单点更新即可。

接下来见证奇迹的时刻:首先,易证当 \(x=1\) 或 \(x=2\) 时,\(f(x)=x\)。

那我们只需要再维护一个区间最大值,如果线段树遍历到的区间最大值 \(\leq 2\),那么直接不用更新了,返回。

这样子似乎复杂度没变?不不不,复杂度已经变成了 \(O(\alpha(a_i)n)\)!

这里给出简单证明过程:首先,\(f(i)\approx \log_{2}(i)\),也就是说,单次 \(f(i)\) 时缩减到了 \(\log(i)\) 级。

然后就是计算,发现 \(x=10^{9}\) 只需要 \(3\) 次!计算次数大致与反 Ackermann 函数同阶(有兴趣的同学自己去证)。

然后理论上每一个元素只会被单点修改 \(3\) 次!所以就是 \(O(\alpha(a_i)n)\) 了!

这就是无标记区间修改线段树。课后习题还有几道无标记区间修改线段树的题,供大家练习。

课后习题:

代码

#include <bits/stdc++.h>
#define int long long
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
using namespace std;

int n,m;
const int N = 1e5+5;
struct node{
	int maxt,sumt;
} t[N<<2];

inline void pushup(int i){
	t[i].maxt=max(t[ls].maxt,t[rs].maxt);
	t[i].sumt=t[ls].sumt+t[rs].sumt;
}

void build(int i,int l,int r){
	if(l==r){
		cin>>t[i].maxt;
		t[i].sumt=t[i].maxt;
		return;
	}
	build(ls,l,mid);
	build(rs,mid+1,r);
	pushup(i);
}

inline int magic(int x){
	return floor(log(x)/log(2)+1);	
}

void update(int ql,int qr,int i,int l,int r){
	if(t[i].maxt<=2){
		return;	
	}
	if(l==r){
		t[i].sumt=t[i].maxt=magic(t[i].sumt);
		return;
	}
	if(ql<=mid){
		update(ql,qr,ls,l,mid);
	}
	if(qr>mid){
		update(ql,qr,rs,mid+1,r);
	}
	pushup(i);
}

int query(int ql,int qr,int i,int l,int r){
	if(ql<=l&&r<=qr){
		return t[i].sumt;
	}
	int ret=0;
	if(ql<=mid){
		ret += query(ql,qr,ls,l,mid);
	}
	if(qr>mid){
		ret += query(ql,qr,rs,mid+1,r);
	}
	return ret;
}

signed main(){
	cin>>n>>m;
	build(1,1,n);
	while(m--){
		int l,r;
		cin>>l>>r;
		update(l,r,1,1,n);
		cout<<query(1,n,1,1,n)<<'\n';
	}
	return 0;
}

标签:qr,log,标记,int,线段,P8618,蓝桥,区间,2014
From: https://www.cnblogs.com/zheyuanxie/p/p8618.html

相关文章

  • P8796 [蓝桥杯 2022 国 AC] 替换字符
    题面给定一个仅含小写英文字母的字符串\(s\)和\(m\)次操作,每次操作选择一个区间\([l_i,r_i]\)将\(s\)的该区间中的所有字母\(x_i\)全部替换成字母\(y_i\),问所......
  • 【题解】Luogu P8743 【[蓝桥杯 2021 省 A] 异或数列】
    最近刚好在刷博弈论,看到这道题没有题解,所以刚好来水一发题目链接[蓝桥杯2021省A]异或数列题目描述Alice和Bob正在玩一个异或数列的游戏。初始时,Alice和Bob......
  • LG2258 [NOIP2014 普及组] 子矩阵
    LG2258[NOIP2014普及组]子矩阵给出一个矩阵,求出一个子矩阵(对应在数列上的定义为子序列,从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵保持行与列的相对顺序......
  • 福建WC2014 路径权值(Kruskal重构树 + 树状数组)
    题目描述:给定一个带权树,树上任意两点间的路径权值\(d\left(x,y\right)\)定义为\(x,y\)这两个点之间路径上的最小值,树上任意一点x的权值定义为这个点到树上其他所有点......
  • 第十三届蓝桥杯省赛C++B组
    《X进制减法》题目连接:https://www.acwing.com/problem/content/4407/贪心,数学推导  我们先来看一下这个65是如何算出来的:321:第一位为二进制,则逢2进1,ans+=1;......
  • P8671 [蓝桥杯 2018 国 AC] 约瑟夫环 题解
    约瑟夫环有\(\mathcalO(n)\)做法相信大家都知道。这里就不在介绍了,这里给出一个不知道这个结论的\(\mathcalO(n\logn)\)简单做法。考虑直接模拟题意,每次循环往后数......
  • 2022年4月第十三届蓝桥杯省赛C组C语言 习题解析(每日一道)
    试题B:特殊时间   【问题描述】           2022年2月22日22:20是一个很有意义的时间,年份为2022,由3个2和1个0组   成,如果将月和日......
  • 【408】2014
    t45每个cache块由标记项、数据区组成!!访问A[0],查TLB未命中,查页表未命中,因此去磁盘调数据(OS有相应的机制去找到页面与磁盘地址的对应关系)调入主存中(同时更新页表和TLB(一般......
  • 蓝桥杯-着急的WYF(不同子串个数)-Suffix Array后缀数组
    前置知识:后缀数组参考链接:https://blog.csdn.net/u013371163/article/details/60469533https://www.bilibili.com/video/BV1sb411t79N?from=search&seid=13723955058308......
  • 第十三届蓝桥杯省赛 B组 C语言
    九进制转十进制顺子日期刷题统计点击查看代码#include<stdio.h>intmain(){ inta,b,n,day=0,i=0;//定义变量和常量 scanf("%d%d%d",&a,......