Can you answer these queries? HDU-4027

时间:2019-09-07
本文章向大家介绍Can you answer these queries? HDU-4027,主要包括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\n",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:\n",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\n",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?'\n':' ');
77         }
78         printf("\n");
79     }
80 //    __clock_t edt = clock();
81 //    printf("Used Time : %.3lfms\n", static_cast<double>(edt - stt)/1000);
82     return 0;
83 }
View Code

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

原文地址:https://www.cnblogs.com/Kiritsugu/p/11479609.html