试题 历届真题 Log大侠【第五届】【决赛】【B组】 资源限制 内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s atm参加了速算训练班,经过刻苦修炼,对以2为底的对数算得飞快,人称Log大侠。 一天,Log大侠的好友 drd 有一些整数序列需要变换,Log大侠正好施展法力... 变换的规则是: 对其某个子序列的每个整数变为: [log_2 (x) + 1] 其中 [] 表示向下取整,就是对每个数字求以2为底的对数,然后取下整。 例如对序列 3 4 2 操作一次后,这个序列会变成 2 3 2。 drd需要知道,每次这样操作后,序列的和是多少。 输入格式 第一行两个正整数 n m 。 第二行 n 个数,表示整数序列,都是正数。 接下来 m 行,每行两个数 L R 表示 atm 这次操作的是区间 [L, R],数列序号从1开始。 输出格式 输出 m 行,依次表示 atm 每做完一个操作后,整个序列的和。 例如,输入: 3 3 5 6 4 1 2 2 3 1 3 程序应该输出: 10 8 6 数据规模和约定 对于 30% 的数据, n, m <= 10^3 对于 100% 的数据, n, m <= 10^5
思路:
- 这种类型就是线段树嘛
- 为了优化时间复杂度,发现一直取log 很容易就把 val的值变得特别小, 到 2和1就不变了,对他们取log2 +1,还是原值
- 所以就是一个势能线段树,对于全是1或者2的区间就不用管
关键吐槽:
最后4个大数据, 第一个 L,R 和蓝桥杯数据对不上,其他都对的上,就很tm离谱,而且暴力题解和我的答案是一样的,我又找了很多篇其他题解都这样,我就搞不明白了!!!!
如果真是蓝桥杯的数据问题,就是纯纯浪费时间!!!!!,
如果不是,求大佬告诉我哪错了
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 100005 template <class G> void read(G &x) { x=0;int f=0;char ch=getchar(); while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x=f?-x:x; return ; } int n,m; long long val[M]; struct dian{ int l,r; long long val; int flag; }p[M*4]; void build(int l,int r,int i) { p[i].l=l;p[i].r=r; if(l==r) { p[i].val=val[l]; if(p[i].val==1||p[i].val==2) p[i].flag=1; else p[i].flag=0; return ; } int mid=(l+r)>>1; build(l,mid,i<<1); build(mid+1,r,i<<1|1); p[i].val=p[i<<1].val+p[i<<1|1].val; p[i].flag=p[i<<1].flag&p[i<<1|1].flag; } void xiu(int l,int r,int i) { if(l>p[i].r||r<p[i].l) return ; if(p[i].flag) return ; if(l<=p[i].l&&r>=p[i].r) { if(p[i].l==p[i].r) { long long tmp=0; while(p[i].val) { tmp++; p[i].val>>=1; } p[i].val=tmp; if(p[i].val==1||p[i].val==2) p[i].flag=1; return ; } } xiu(l,r,i<<1); xiu(l,r,i<<1|1); p[i].val=p[i<<1].val+p[i<<1|1].val; p[i].flag=p[i<<1].flag&p[i<<1|1].flag; } int main(){ read(n);read(m); for(ri i=1;i<=n;i++) { read(val[i]); } build(1,n,1); for(ri i=1;i<=100;i++) { int l,r; read(l);read(r); xiu(l,r,1); printf("%lld\n",p[1].val); } return 0; }