codevs2492 上帝造题的七分钟 2

2492 上帝造题的七分钟 2

题目描述 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

【思路】

      区间查询+打标记。

  一个关键的思想就是一个数被反复开方并向下取整最终会变为1,如果一个数变成1就不需要对它操作了。

  对于区间开方操作,对于区间中的每一个点都进行操作如果为1则下次不再操作。

  实现1:

         BIT+“并查集”。

【代码1】

 1 //341ms
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 7 using namespace std;
 8 
 9 typedef long long LL;
10 const int maxn = 200000+10;
11 
12 LL a[maxn],p[maxn];
13 int n,m;
14 
15 LL read() {
16     char c=getchar();
17     while(!isdigit(c)) c=getchar();
18     LL x=0;
19     while(isdigit(c)) {
20         x=x*10+c-'0';
21         c=getchar();
22     }
23     return x;
24 }
25 
26 LL c[maxn];
27 int lowbit(int x) { return x&(-x); }
28 LL Sum(LL x) {
29     LL res=0;
30     while(x>0) {
31         res += c[x];
32         x-=lowbit(x);
33     }
34     return res;
35 }
36 void Add(int x,LL d) {
37     while(x<=n) {
38         c[x] += d;
39         x += lowbit(x);
40     }
41 }
42 int find(int x) {
43     return x==p[x]?x:p[x]=find(p[x]);
44 }
45 
46 int main() {
47     n=read();
48     FOR(i,1,n) a[i]=read(),Add(i,a[i]);
49     FOR(i,1,n+1) p[i]=i;                //n+1为哨兵 
50     m=read();
51     LL u,v,w;
52     FOR(i,1,m) {
53         w=read(),u=read(),v=read();
54         if(u>v) swap(u,v);
55         
56         if(w)
57             printf("%lld
",Sum(v)-Sum(u-1));
58         else 
59         {
60             for(int j=find(u);j<=v;j=find(j+1)) {
61                 LL s=sqrt(a[j]);
62                 Add(j,s-a[j]);
63                 a[j]=s;
64                 if(s==1) {
65                     p[j]=j+1;
66                     if(j==v) break;
67                 }
68             }
69         }
70     }
71     return 0;
72 }
View Code

  实现2:

         线段树+结点标记

【代码2】

 1 //399ms
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 7 using namespace std;
 8 
 9 typedef long long LL;
10 const int maxn = 500000+10;
11 
12 LL a[maxn],p[maxn];
13 int n,m;
14 
15 LL read() {
16     char c=getchar();
17     while(!isdigit(c)) c=getchar();
18     LL x=0;
19     while(isdigit(c)) {
20         x=x*10+c-'0';
21         c=getchar();
22     }
23     return x;
24 }
25 
26 LL sumv[maxn];
27 bool f[maxn];
28 void build(int u,int L,int R) {
29     int lc=u*2,rc=u*2+1;
30     if(L==R) {
31         sumv[u]=a[L];
32     }
33     else {
34         int M=L+(R-L)/2;
35         build(lc,L,M);
36         build(rc,M+1,R);
37         sumv[u]=sumv[lc]+sumv[rc];
38     }
39 }
40 int ya,yb;
41 void update(int u,int L,int R) {
42     int lc=u*2,rc=u*2+1;
43     if(f[u]) return ;
44     if(L==R) {
45         sumv[u]=sqrt(sumv[u]);
46         if(sumv[u]==1) f[u]=1;
47     }
48     else {
49         int M=L+(R-L)/2;
50         if(ya<=M) update(lc,L,M);
51         if(M<yb)  update(rc,M+1,R);
52         
53         sumv[u]=sumv[lc]+sumv[rc];
54         f[u]=f[lc]&&f[rc];
55     }
56 }
57 LL query(int u,int L,int R) {
58     int lc=u*2,rc=u*2+1;
59     if(ya<=L && R<=yb) {
60         return sumv[u];
61     }
62     else {
63         int M=L+(R-L)/2;
64         LL res=0;
65         if(ya<=M) res+=query(lc,L,M);
66          if(M<yb)  res+=query(rc,M+1,R);
67          return res;
68     }
69 }
70 
71 int main() {
72     n=read();
73     FOR(i,1,n) a[i]=read();
74     build(1,1,n);
75     m=read();
76     int w;
77     while(m--) {
78         w=read(),ya=read(),yb=read();
79         if(ya>yb) swap(ya,yb);
80         if(w)    printf("%lld
",query(1,1,n));
81         else update(1,1,n);
82     }
83     return 0;
84 }
View Code
原文地址:https://www.cnblogs.com/lidaxin/p/4977619.html