题目大意:
一个长度为n的序列,初始化序列中的元素为1。接下来执行Q次更新操作,每次操作将区间[x,y]上的值更新为z。所有操作结束后,求出序列的总和。
思路:
成段更新的线段树的模板题。
代码:
因为之前没有做过成段更新的线段树,所以这次依据此题做出模板,下面是模板代码。
#include<iostream> #include<stdio.h> using namespace std; #define MAXSIZE 100000 int val[MAXSIZE+1]; struct node { int total; //区间属性,这里是total,表示区间元素和。 int left; int right; int mark; //mark表示延迟标记 }tree[MAXSIZE*3]; int create(int root,int left,int right) //以root为根节点建树。 { tree[root].mark=0; tree[root].left=left; tree[root].right=right; if(left==right) return tree[root].total=val[left]; int middle=(left+right)/2; return tree[root].total=create(2*root,left,middle)+create(2*root+1,middle+1,right); } void updata_mark(int root) //更新root的子节点的延迟标记。 { if(tree[root].mark) { tree[root].total=tree[root].mark*(tree[root].right-tree[root].left+1); if(tree[root].left!=tree[root].right) tree[root*2].mark=tree[root*2+1].mark=tree[root].mark; tree[root].mark=0; } } int calculate(int root,int left,int right) //以root为根节点的线段树中,求取区间[left,right]的元素和。 { updata_mark(root); if(tree[root].left>right||tree[root].right<left) return 0; if(left<=tree[root].left&&tree[root].right<=right) return tree[root].total; return calculate(2*root,left,right)+calculate(2*root+1,left,right); } int updata(int root,int left,int right,int val) //以root为根节点的线段树中,将区间[left,right]中的元素更新为val。 { updata_mark(root); if(tree[root].left>right||tree[root].right<left) return tree[root].total; if(left<=tree[root].left&&tree[root].right<=right) { tree[root].mark=val; return tree[root].total=val*(tree[root].right-tree[root].left+1); } return tree[root].total=updata(2*root,left,right,val)+updata(2*root+1,left,right,val); } int main() { int t; scanf("%d",&t); for(int i=1,n,q;i<=t;i++) { scanf("%d%d",&n,&q); for(int j=1;j<=n;j++) val[j]=1; create(1,1,n); for(int j=0,x,y,z;j<q;j++) { scanf("%d%d%d",&x,&y,&z); updata(1,x,y,z); } printf("Case %d: The total value of the hook is %d.\n",i,calculate(1,1,n)); } }
由于题目中给出了序列元素均初始化为1以及只需考虑序列总和等条件,针对本题对代码进行精简,主要是除去了calculate()函数和val[]数组。
#include<iostream> #include<stdio.h> using namespace std; #define MAXSIZE 100000 struct node { int total; int left; int right; int mark; }tree[MAXSIZE*3]; int create(int root,int left,int right) { tree[root].mark=0; tree[root].left=left; tree[root].right=right; if(left==right) return tree[root].total=1; int middle=(left+right)/2; return tree[root].total=create(2*root,left,middle)+create(2*root+1,middle+1,right); } void updata_mark(int root) { if(tree[root].mark) { tree[root].total=tree[root].mark*(tree[root].right-tree[root].left+1); if(tree[root].left!=tree[root].right) tree[root*2].mark=tree[root*2+1].mark=tree[root].mark; tree[root].mark=0; } } int updata(int root,int left,int right,int val) { updata_mark(root); if(tree[root].left>right||tree[root].right<left) return tree[root].total; if(left<=tree[root].left&&tree[root].right<=right) { tree[root].mark=val; return tree[root].total=val*(tree[root].right-tree[root].left+1); } return tree[root].total=updata(2*root,left,right,val)+updata(2*root+1,left,right,val); } int main() { int t; scanf("%d",&t); for(int i=1,n,q;i<=t;i++) { scanf("%d%d",&n,&q); create(1,1,n); for(int j=0,x,y,z;j<q;j++) { scanf("%d%d%d",&x,&y,&z); updata(1,x,y,z); } printf("Case %d: The total value of the hook is %d.\n",i,tree[1].total); } }