Big Water Problem (线段树)
题目描述
给一个数列,会有多次询问,对于每一次询问,会有两种操作:
1:给定两个整数x, y, 然后在原数组的第x位置上加y;
2:给定两个整数l,r,然后输出数组从第l位加到第r位数字的和并换行
输入描述:
第一行有两个整数n, m(1 <= n, m <= 100000)代表数列的长度和询问的次数
第二行n个数字,对于第i个数字a[i],(0<=a[i]<=100000)。
接下来m行,每一行有三个整数f, x, y。第一个整数f是1或者是2,代表操作类型,如果是1,接下来两个数x,y代表第x的位置上加y,如果是2,则求x到y的和,保证数据合法。
输出描述:
输出每次求和的结果并换行
示例1
输入
10 2
1 2 3 4 5 6 7 8 9 10
1 1 9
2 1 10
输出
64
思路:线段树的单点修改加区间查询......
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<cmath>
5 #include<algorithm>
6 #include<map>
7 #include<set>
8 #include<vector>
9 using namespace std;
10 #define ll long long
11 const int inf=99999999;
12 const int mod=1e9+7;
13 const int maxn=100000+10;
14 typedef struct
15 {
16 int left;
17 int right;
18 ll int weight;
19 ll int lan;
20 } St;
21 St tree[maxn<<2];
22 int n,m;
23 int a,b;
24 ll int ans;
25 ll int num;
26 inline void build_tree(int k,int left,int right)//建树
27 {
28 tree[k].left=left;
29 tree[k].right=right;
30 if(left==right)
31 {
32 cin>>tree[k].weight;
33 return ;
34 }
35 int mid=(left+right)>>1;
36 build_tree(k<<1,left,mid);//左子树
37 build_tree(k<<1|1,mid+1,right);//右子树
38 tree[k].weight=tree[k<<1].weight+tree[k<<1|1].weight;//状态合并,该节点权重等于左子树加右子树权重
39 }
40 inline void lan_down(int k)//树懒标记下传
41 {
42 tree[k<<1].lan+=tree[k].lan;
43 tree[k<<1|1].lan+=tree[k].lan;
44 tree[k<<1].weight+=tree[k].lan*(tree[k<<1].right-tree[k<<1].left+1);
45 tree[k<<1|1].weight+=tree[k].lan*(tree[k<<1|1].right-tree[k<<1|1].left+1);
46 tree[k].lan=0;
47 }
48 inline void ask_point(int k)//单点查询
49 {
50 if(tree[k].left==tree[k].right)
51 {
52 ans=tree[k].weight;
53 return ;
54 }
55 if(tree[k].lan)
56 lan_down(k);
57 int mid=(tree[k].left+tree[k].right)>>1;
58 if(a<=mid)//a表示单点询问位置
59 ask_point(k<<1);//目标位置靠左,递归左孩子
60 else
61 ask_point(k<<1|1);//目标位置靠右,递归右孩子
62 }
63 inline void add_point(int k)//单点修改
64 {
65 if(tree[k].left==tree[k].right)
66 {
67 tree[k].weight+=num;//单点增加num
68 return ;
69 }
70 if(tree[k].lan)//树懒标记下传
71 lan_down(k);
72 int mid=(tree[k].left+tree[k].right)>>1;
73 if(a<=mid)
74 add_point(k<<1);
75 else
76 add_point(k<<1|1);
77 tree[k].weight=tree[k<<1].weight+tree[k<<1|1].weight;//状态合并
78 }
79 inline void ask_qujian(int k)//区间查询
80 {
81 if(tree[k].left>=a&&tree[k].right<=b)//包含了left,right当前区间,全加上
82 {
83 ans+=tree[k].weight;
84 return ;
85 }
86 if(tree[k].lan)//树懒标记下传
87 lan_down(k);
88 int mid=(tree[k].left+tree[k].right)>>1;
89 if(a<=mid)//递归查询左子区间
90 ask_qujian(k<<1);
91 if(b>mid)//递归查询右子区间
92 ask_qujian(k<<1|1);
93 }
94 inline void add_qujian(int k)//区间修改
95 {
96 if(tree[k].left>=a&&tree[k].right<=b)
97 {
98 tree[k].weight+=num*(tree[k].right-tree[k].left+1);
99 tree[k].lan+=num;
100 return ;
101 }
102 if(tree[k].lan)
103 lan_down(k);
104 int mid=(tree[k].left+tree[k].right)>>1;
105 if(a<=mid)
106 add_qujian(k<<1);
107 if(b>mid)
108 add_qujian(k<<1|1);
109 tree[k].weight=tree[k<<1].weight+tree[k<<1|1].weight;//状态合并
110 }
111 int main()
112 {
113 ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
114 cin>>n>>m; //n个节点,m个操作
115 build_tree(1,1,n);//建树
116 int op;
117 for(int i=0;i<m;i++)
118 {
119 cin>>op;
120 if(op&1)
121 {
122 cin>>a>>num;
123 add_point(1);//单点修改
124 }
125 else
126 {
127 cin>>a>>b;
128 ans=0;
129 ask_qujian(1);
130 cout<<ans<<endl;
131 }
132 }
133 return 0;
134 }
大佬见笑,,