59
现在正在熟悉线段树的算法,这是第一个ac的线段树题目
以下用的left与right都是下标
创建原理:假如左右两边的值分别是1与5,然后会又分成1与3、4与5,然后1与3又会分成1与2、3,然后1与2会又被分成1、2,最后输入的程序还是从头开始,按顺序输入
#include<stdio.h> #include<string.h> #include <string> #include <queue> #include <iostream> using namespace std; typedef struct node{ int l,r,value; }temp; int ans; temp node[200000]; void add(int rt) //求值 { node[rt].value=node[rt<<1].value+node[rt<<1|1].value; } void init(int left,int right,int rt) //创建 { //这里的left和right确定了创建范围的大小 node[rt].l=left; node[rt].r=right; if (left==right) { scanf("%d",&node[rt].value); return; } int mid=(left+right)>>1; init(left,mid,rt<<1); init(mid+1,right,rt<<1|1); add(rt); } void update(int left,int right,int rt,int pos,int cnt) //更新 { //这里的left和right确定了更新的范围,pos是指要查找的东西下标 if (left==right) { node[rt].value+=cnt; return; } int mid=(left+right)>>1; if (pos<=mid) update(left,mid,rt<<1,pos,cnt); else update(mid+1,right,rt<<1|1,pos,cnt); add(rt); } void query(int left,int right,int rt,int l,int r) //访问输出 { //这里的left与right确定了更新的范围,而l与r确定了需要访问的范围 if (l<=left&&r>=right) { ans+=node[rt].value; return; } int mid=(left+right)>>1; if (r<=mid) query(left,mid,rt<<1,l,r); else if (l>mid) query(mid+1,right,rt<<1|1,l,r); else { query(left,mid,rt<<1,l,r); query(mid+1,right,rt<<1|1,l,r); } } int main() { int t,n,k; char str[10]; scanf("%d",&t); for (k=1;k<=t;k++) { scanf("%d",&n); init(1,n,1); printf("Case %d:\n",k); while (scanf("%s",str)) { if (strcmp(str,"End")==0) break; int a,b; scanf("%d%d",&a,&b); if (strcmp(str,"Query")==0) { ans=0; query(1,n,1,a,b); printf("%d\n",ans); } if (strcmp(str,"Sub")==0) update(1,n,1,a,-b); else update(1,n,1,a,b); } } return 0; }