[Codevs] 2492 上帝造题的七分钟2

2492 上帝造题的七分钟 2

 时间限制: 1 s
 空间限制: 64000 KB
 题目等级 : 大师 Master
 
题目描述 Description

  XLk觉得《上帝造题的七分钟》不太过瘾,于是有了第二部。

  "第一分钟,X说,要有数列,于是便给定了一个正整数数列。
  第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作。
  第三分钟,k说,要能查询,于是便有了求一段数的和的操作。
  第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围。
  第五分钟,诗人说,要有韵律,于是便有了时间限制和内存限制。
  第六分钟,和雪说,要省点事,于是便有了保证运算过程中及最终结果均不超过64位有符号整数类型的表示范围的限制。
  第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。"
  ——《上帝造题的七分钟·第二部》
  所以这个神圣的任务就交给你了。

输入描述 Input Description

  第一行一个整数n,代表数列中数的个数。
  第二行n个正整数,表示初始状态下数列中的数。
  第三行一个整数m,表示有m次操作。
  接下来m行每行三个整数k,l,r,k=0表示给[l,r]中的每个数开平方(下取整),k=1表示询问[l,r]中各个数的和。
  UPD:注意数据中有可能l>r,所以遇到这种情况请交换l和r。

 
输出描述 Output Description

  对于询问操作,每行输出一个回答。

 
样例输入 Sample Input

10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8

 
样例输出 Sample Output

19
7
6

 
数据范围及提示 Data Size & Hint

  对于30%的数据,1<=n,m<=1000,数列中的数不超过32767。
  对于100%的数据,1<=n,m<=100000,1<=l,r<=n,数列中的数大于0,且不超过1e12。
  注意l有可能大于r,遇到这种情况请交换l,r。

来源:Nescafe 20

分析 Analysis

这道题被自己搞的无比复杂= =

再次死在追求正解的道路上= =

根据hzwer的方法:单点暴力修改,区间求和

(也就区间求和是线段树特性,单点暴力= =)

本来以为必爆,但是分析复杂度发现 --不会爆qwq

所以其实 hzwer 的优化就加了一个:

对于一段连续区间,如果都是1,显然没必要继续开方,直接跳过

那么在线段树版本中,如果一个子树整个的都是1,那么修改的时候就可以直接跳过了

------------------------------------------------------------------------

然而据说正解是 树状数组+并查集 ?

不过其实我不应该纠结正解 --能做而且不会爆就好

毕竟不知道死在正解上多少次了

树状数组+并查集 => 单点修改+区间求和+小优化

小优化即上文所说的跳过11111111111111...

代码 Code

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #define LL long long
 5 #define mid (L+R)/2
 6 #define lc (rt<<1)
 7 #define rc (rt<<1|1)
 8 #define maxn 1000000
 9 using namespace std;
10 
11 struct node{
12     LL sum,flag;
13 }Tree[maxn*4];
14 
15 int n,m;LL a,b,c;
16 
17 void maintain(int rt){
18     Tree[rt].sum = Tree[lc].sum + Tree[rc].sum;
19     Tree[rt].flag = Tree[lc].flag&Tree[rc].flag;
20 }
21 
22 void build(int rt,int L,int R){
23     if(L == R){
24         scanf("%lld",&Tree[rt].sum);
25         if(Tree[rt].sum == 1 || Tree[rt].sum == 0) Tree[rt].flag = 1;
26         else Tree[rt].flag = 0;
27     }else{
28         build(lc,L,mid);
29         build(rc,mid+1,R);
30         
31         maintain(rt);
32     }
33 }
34 
35 void modify(int rt,int L,int R,int qL,int qR){
36     
37     if(Tree[rt].flag) return;
38     
39     if(L == R){
40         Tree[rt].sum = (LL)sqrt(Tree[rt].sum);
41         if(Tree[rt].sum == 1 || Tree[rt].sum == 0) Tree[rt].flag = 1;
42     }else{
43         
44         if(qL <= mid) modify(lc,L,mid,qL,qR);
45         if(qR > mid) modify(rc,mid+1,R,qL,qR);
46         
47         maintain(rt);
48     }
49 }
50 
51 LL query(int rt,int L,int R,int qL,int qR){
52     
53 //    if(Tree[rt].flag) return (R-L+1);
54     
55     if(qL <= L && R <= qR){
56         return Tree[rt].sum;
57     }else{
58         LL ans = 0;
59         if(qL <= mid) ans += query(lc,L,mid,qL,qR);
60         if(qR > mid) ans += query(rc,mid+1,R,qL,qR);
61         
62         return ans;
63     }
64 }
65 
66 int main(){
67     scanf("%d",&n);
68     build(1,1,n);
69     scanf("%d",&m);
70     
71     for(int i = 1;i <= m;i++){
72         scanf("%lld%lld%lld",&a,&b,&c);
73         if(b > c) swap(b,c);
74         if(a) printf("%lld
",query(1,1,n,b,c));
75         else modify(1,1,n,b,c);
76     }
77     
78     return 0;
79 }
线段树 版本
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #define maxn 1000000
 5 #define LL long long
 6 #define lowbit(x) (-x&x)
 7 using namespace std;
 8 
 9 LL Tree[maxn],n,m,a,b,c,cnt,arr[maxn];
10 void add(LL pos,LL val){
11     while(pos <= n){
12         Tree[pos] += val;
13         pos += lowbit(pos);
14     }
15 }LL sum(LL pos){
16     LL ans = 0;
17     if(!pos) return ans;
18     while(pos > 0){
19         ans += Tree[pos];
20         pos -= lowbit(pos);
21     }return ans;
22 }
23 
24 LL pre[maxn];
25 LL find(LL x){
26     if(!pre[x]) return x;
27     else{
28         pre[x] = find(pre[x]);
29         return pre[x];
30     }
31 }void unite(LL u,LL v){
32     if(find(u)!=find(v)) pre[find(u)] = find(v);
33 }
34 
35 int main(){
36     scanf("%lld",&n);
37     for(LL i = 1;i <= n;i++){
38         scanf("%lld",&arr[i]);
39         add(i,arr[i]);
40 //        for(int i = 1;i <= n;i++){
41 //            printf("%lld ",sum(i));
42 //        }cout << endl;
43     }
44     
45     scanf("%lld",&m);
46     for(LL i = 1;i <= m;i++){
47         scanf("%lld%lld%lld",&a,&b,&c);
48         
49         if(b > c) swap(b,c);
50         if(a){
51             printf("%lld
",sum(c)-sum(b-1));
52         }else{
53             for(LL j = find(b);j <= c;j = find(j+1)){
54                 if(j == 0) break;
55                 add(j,-arr[j]);
56                 arr[j] = (LL)sqrt(arr[j]);
57                 add(j,arr[j]);
58                 if(arr[j] == 1) pre[j] = j+1;
59             }
60         }
61     }
62     
63     return 0;
64 }
树状数组+并查集 版本
转载请注明出处 -- 如有意见欢迎评论
原文地址:https://www.cnblogs.com/Chorolop/p/7454927.html