标题:Log大侠
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 每做完一个操作后,整个序列的和。
这题暴力肯定可以得一部分的,区间大小最差的情况就是每次都给L=1,R=N,这时暴力肯定不行的,会写线段树的话,可以看出这题也就是单点更新以及总区间查询。而它没说数据范围,但就算是1e18的话,取log对于每个位置的数来说,它最多也就更新个60次左右,所以我们可以加个标记,代表这个区间内还有没有位置需要更新,然后再线段树维护,时间复杂度就是60*nlog(n)这样。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cmath> 3 #define L(x) (x<<1) 4 #define R(x) (x<<1|1) 5 #define M(x) ((T[x].l+T[x].r)>>1) 6 typedef long long ll; 7 const int N=100118; 8 struct Tree{ 9 bool flag; 10 int l,r; 11 ll sum; 12 }T[N<<2]; 13 ll a[N]; 14 void built(int id,int l,int r) 15 { 16 T[id].l=l; 17 T[id].r=r; 18 T[id].sum=0; 19 T[id].flag=false; 20 if(l==r) 21 { 22 T[id].sum=a[l]; 23 T[id].flag=(a[l]>2ll); 24 return ; 25 } 26 built(L(id),l,M(id)); 27 built(R(id),M(id)+1,r); 28 T[id].flag=T[L(id)].flag|T[R(id)].flag; 29 T[id].sum=T[L(id)].sum+T[R(id)].sum; 30 } 31 void modify(int id,int l,int r) 32 { 33 if(!T[id].flag) 34 return ; 35 if(T[id].l==T[id].r) 36 { 37 T[id].sum=(ll)floor(log2(1.0*T[id].sum)+1.0); 38 T[id].flag=(T[id].sum>2ll); 39 return ; 40 } 41 if(l<=M(id)) 42 modify(L(id),l,r); 43 if(r>M(id)) 44 modify(R(id),l,r); 45 T[id].flag=T[L(id)].flag|T[R(id)].flag; 46 T[id].sum=T[L(id)].sum+T[R(id)].sum; 47 } 48 int main() 49 { 50 int n,m,l,r; 51 scanf("%d%d",&n,&m); 52 for(int i=1;i<=n;i++) 53 scanf("%lld",&a[i]); 54 built(1,1,n); 55 while(m--) 56 { 57 scanf("%d%d",&l,&r); 58 modify(1,l,r); 59 printf("%lld\n",T[1].sum); 60 } 61 return 0; 62 }
不懂线段树的话,知道stl的map的话,还有种map的写法,思路一样,当某个位置的值<=2时就把它从map删去。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cmath> 3 #include<map> 4 using namespace std; 5 typedef long long ll; 6 map<int,ll> mmp; 7 map<int,ll>::iterator b,e,temp; 8 int main() 9 { 10 int n,m,l,r; 11 ll sum=0; 12 scanf("%d%d",&n,&m); 13 for(int i=1;i<=n;i++) 14 { 15 scanf("%lld",&mmp[i]); 16 sum+=mmp[i]; 17 } 18 while(m--) 19 { 20 scanf("%d%d",&l,&r); 21 b=mmp.lower_bound(l); 22 e=mmp.upper_bound(r); 23 while(b!=e) 24 { 25 temp=b; 26 b++; 27 sum-=temp->second; 28 temp->second=(ll)floor(1.0*log2(temp->second)+1.0); 29 sum+=temp->second; 30 if(temp->second<=2) 31 mmp.erase(temp); 32 } 33 printf("%lld\n",sum); 34 } 35 return 0; 36 }