zoukankan      html  css  js  c++  java
  • 蓝桥 log大侠


    标题: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)这样。

     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
    ",T[1].sum);
    60     }
    61     return 0;
    62 }
    线段树下线段果

      不懂线段树的话,知道stl的map的话,还有种map的写法,思路一样,当某个位置的值<=2时就把它从map删去。

     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
    ",sum);
    34     }
    35     return 0;
    36 }
    STLwd
  • 相关阅读:
    福大软工1816 · 第五次作业
    福大软工1816 · 第四次作业
    第三次作业
    福大软工1816 · 第二次作业
    培养孩子应知的30个细节
    人力资源六大模块
    中小学班主任工作规定
    事业单位笔试题
    班级管理
    Leetcode 7 反转整数
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/10907731.html
Copyright © 2011-2022 走看看