• Can you answer these queries? HDU-4027


    题目链接

    题目大意是一个长度为 N (N<=1e5)的区间,区间里元素都是正整数,现在有M(M<=1e5)次区间修改与查询,区间修改的操作L,R会将[L,R]区间里面的所有元素开方(向下取整),区间查询会询问[L,R]的区间和,保证区间和小于 2^63,多组样例输入。

    开始拿到这个题思路有些停滞,因为这个修改区间里每个元素的修改是不同的,而查询又是区间和,每个数字被开方到1的次数是很少的所以想从lazy标记下手存区间修改次数,查询时下推但又担心复杂度。

    后来再发现通过剪枝可以很好解决复杂度的问题,就算单个元素是 2^64 大小,其被开方到1也只用6次,开始进行暴力的修改叶结点,如果在修改时发现区间和全为1就不需要再往下搜索,这样叶结点最多被访问6次,其它结点被访问最糟糕也是在单点修改的情况下:最多十七层( 0<=i <17,17为logN)而每层结点被访问的次数和都是 6*(2^i)*(N/(2^i)) ,何况单个元素小于 2^63 ,所以修改的总开销是 O(constant*NlogN),而查询仍是一次O(logN),也不会超过M次,复杂度OK。

     1 #pragma optimize("O3","unroll-loops")
     2 #pragma target("avx3")
     3 
     4 #include <bits/stdc++.h>
     5 using namespace std;
     6 #define Lson(x) ((x)<<1)
     7 #define Rson(x) ((x)<<1|1)
     8 typedef long long ll;
     9 const int maxn = 1e5;
    10 ll raw[maxn+10];
    11 ll d[(maxn<<2)+10];
    12 
    13 void build(int s,int t,int p){
    14     if(s == t){
    15         d[p] = raw[s];
    16         return;
    17     }
    18     int mid = (s + t) >> 1;
    19     build(s,mid,Lson(p));
    20     build(mid+1,t,Rson(p));
    21     d[p] = d[Lson(p)] + d[Rson(p)];
    22 }
    23 
    24 void update(int L,int R,int s,int t,int p){
    25 //    printf("%d %d %d %d
    ",L,R,s,t);
    26     if(d[p] <= 1ll*(t-s+1))
    27         return ;
    28     if(L == s && t == R && d[p] == (t-s+1))
    29         return ;
    30     if(s == t){
    31         d[p] = sqrt(d[p]);
    32         return ;
    33     }
    34     int mid = (s + t) >> 1;
    35     if(R<=mid) update(L,R,s,mid,Lson(p));
    36     else if(L > mid) update(L,R,mid+1,t,Rson(p));
    37     else update(L,mid,s,mid,Lson(p)) , update(mid+1,R,mid+1,t,Rson(p));
    38     d[p] = d[Lson(p)] + d[Rson(p)];
    39 }
    40 
    41 ll query(int L,int R,int s,int t,int p){
    42     if(L == s && t == R){
    43         return d[p];
    44     }
    45     int mid = (s + t) >> 1;
    46     ll sum = 0;
    47     if(R<=mid) sum += query(L,R,s,mid,Lson(p));
    48     else if(L > mid) sum += query(L,R,mid+1,t,Rson(p));
    49     else sum = query(L,mid,s,mid,Lson(p)) + query(mid+1,R,mid+1,t,Rson(p));
    50     return sum;
    51 }
    52 
    53 int main(){
    54 //    __clock_t stt = clock();
    55     int cntcase =0 ;
    56     int N;
    57     while(scanf("%d",&N)==1){
    58         for(int i=1;i<=N;++i){
    59             scanf("%lld",&raw[i]);
    60         }
    61         build(1,N,1);
    62 
    63         int M;
    64         scanf("%d",&M);
    65         cntcase ++;
    66         printf("Case #%d:
    ",cntcase);
    67         for(int i=0;i<M;++i){
    68             int op,L,R;
    69             scanf("%d%d%d",&op,&L,&R);
    70             if(L>R) swap(L,R);
    71             if(op)
    72                 printf("%lld
    ",query(L,R,1,N,1));
    73             else
    74                 update(L,R,1,N,1);
    75 //            for(int j=1;j<=N;++j)
    76 //                printf("%lld%c",query(j,j,1,N,1),j==N?'
    ':' ');
    77         }
    78         printf("
    ");
    79     }
    80 //    __clock_t edt = clock();
    81 //    printf("Used Time : %.3lfms
    ", static_cast<double>(edt - stt)/1000);
    82     return 0;
    83 }
    View Code

    这题坑的地方还有一个,就是给出的区间并不是 L <= R 的需要判断一下swap ,因为这个TLE了好几次,还怀疑自己复杂度出问题了用随机大数据测了好几回,最后才发现题目Input里没做L,R的大小限制。通过这道题倒是让我觉得线段树和搜索在本质上有一定的相似。

  • 相关阅读:
    Groovy Closure & Action
    Groovy A simple DSL based on groovy
    Groovy 一些小细节
    Android 那些年踩过的坑
    Android Startup
    Android 开发最佳实践
    Android 开发经验-容易忽略的问题
    Android 开发经验-Fragment相关
    AQTime + Delphi
    关于ANSI,unicode与utf-8的区别
  • 原文地址:https://www.cnblogs.com/Kiritsugu/p/11479609.html
Copyright © 2020-2023  润新知