【线段树/区间开平方】BZOJ3211-花神游历各国

【题目大意】

给出一些数,有两种操作。(1)将区间内每一个数开方(2)查询每一段区间的和

【思路】

普通的线段树保留修改+开方优化。可以知道当一个数为0或1时,无论开方几次,答案仍然相同。所以设置flag=1。如果一个节点的左右孩子flag均为1,那么它的flag也是1。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define lson l,m,rt<<1
 7 #define rson m+1,r,rt<<1|1
 8 #define LL long long
 9 using namespace std;
10 const int MAXN=100000+500;
11 int n,m;
12 LL sum[MAXN<<2];
13 int flag[MAXN<<2];
14 
15 void pushup(int rt)
16 {
17     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
18     flag[rt]=flag[rt<<1]&flag[rt<<1|1]; 
19 }
20 
21 void build(int l,int r,int rt)
22 {
23     flag[rt]=0;
24     if (l==r)
25     { 
26         scanf("%lld",&sum[rt]);
27         return;
28     }
29     int m=(l+r)>>1;
30     build(lson);
31     build(rson); 
32     pushup(rt);
33 }
34 
35 void update(int L,int R,int l,int r,int rt)
36 {
37     if (flag[rt]) return;
38     if (l==r)
39     {
40         sum[rt]=(LL)sqrt(sum[rt]);
41         if (sum[rt]==0 || sum[rt]==1) flag[rt]=1;
42         return;
43     }
44     int m=(l+r)>>1;
45     if (L<=m) update(L,R,lson);
46     if (R>m) update(L,R,rson);
47     pushup(rt);
48 }
49 
50 LL query(int L,int R,int l,int r,int rt)
51 {
52     if (L<=l && r<=R) return sum[rt];
53     int m=(l+r)>>1;
54     LL ret=0;
55     if (L<=m) ret+=query(L,R,lson);
56     if (R>m) ret+=query(L,R,rson);
57     return ret;
58 }
59 
60 int main()
61 {
62     scanf("%d",&n);
63     build(1,n,1);
64     scanf("%d",&m);
65     for (int i=0;i<m;i++)
66     {
67         int x,l,r;
68         scanf("%d%d%d",&x,&l,&r);
69         if (x==1) printf("%lld\n",query(l,r,1,n,1));
70             else update(l,r,1,n,1);
71     }
72     return 0;
73 } 

 

posted @ 2016-03-08 19:00  iiyiyi  阅读(627)  评论(0编辑  收藏  举报