2019年第二阶段我要变强个人训练赛第八场 B.序列(seq)

传送门

 

B.序列(seq)

题目描述

  给出一个长度为n的序列a,每次对序列进行一下的某一个操作。

输入

  第一行两个整数n,q表示序列长度和操作个数。

接下来一行n个数,表示序列a。

接下来q行表示操作,其格式见题目描述。

输出

见题目描述。

题解

单点修改区间查询,但是坑点在于单点修改超时,如果一个值小于等于1开根不受影响,所以可以不去耗时间修改它;
具体实现方法就是叶子节点定义一个变量f代表是否需要修改如果小于等于1就不需要然后向上传递p=p<<1&p<<1|1就行了;

AC代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 struct node
 4 {
 5     int l,r,f;
 6     long long v;
 7 }t[400005];
 8 long long a[100005];
 9 void build(int p,int l,int r)
10 {
11     t[p].l=l;
12     t[p].r=r;
13     t[p].f=0;
14     if(l==r)
15     {
16         t[p].v=a[l];
17         return;
18     }
19     int mid=(l+r)>>1;
20     build(p<<1,l,mid);
21     build(p<<1|1,mid+1,r);
22     t[p].v=t[p<<1].v+t[p<<1|1].v;
23     t[p].f=t[p<<1].f&t[p<<1|1].f;
24 }
25 void change(int p,int x,int y)
26 {
27     if(t[p].l==t[p].r)
28     {
29         t[p].v=sqrt(t[p].v);
30         if(t[p].v<=1)
31         t[p].f=1;
32         return;
33     }
34     int mid=(t[p].l+t[p].r)>>1;
35     if(x<=mid&&!t[p<<1].f)
36     change(p<<1,x,y);
37     if(y>mid&&!t[p<<1|1].f)
38     change(p<<1|1,x,y);
39     t[p].v=t[p<<1].v+t[p<<1|1].v;
40     t[p].f=t[p<<1].f&t[p<<1|1].f;
41 }
42 long long sum(int p,int x,int y)
43 {
44     if(x<=t[p].l&&y>=t[p].r)
45     return t[p].v;
46     int mid=(t[p].l+t[p].r)>>1;
47     long long ans=0;
48     if(x<=mid)
49     ans+=sum(p<<1,x,y);
50     if(y>mid)
51     ans+=sum(p<<1|1,x,y);
52     return ans;
53 }
54 int main()
55 {
56     int n,m;
57     scanf("%d%d",&n,&m);
58     for(int i=1;i<=n;i++)
59     scanf("%lld",&a[i]);
60     build(1,1,n);
61     while(m--)
62     {
63         int a,b,c;
64         scanf("%d%d%d",&a,&b,&c);
65         if(a==1)
66         printf("%lld\n",sum(1,b,c));
67         else
68         change(1,b,c);
69     }
70 }
View Code

题解来源(by mhr)

 

 

posted @ 2019-06-10 19:13  HHHyacinth  阅读(207)  评论(0编辑  收藏  举报