题目链接:戳我戳我
题目大意:
给出一段序列,一开始每个数字的价值都是1,通过一些操作把某些区间数的价值改为2或者3,最后输出这段序列的总价值。
题目思路:
算是比较裸的线段树模板题了(毕竟我这种菜鸡都能做出来T_T)显然是求区间和,只不过输入数字是多少(2或3),就把该区间的值改为2*区间长度或者3*区间长度,至于子节点的修改,完全参照区间修改的tag操作就行。注意这道题不是累加,因为并不是要把区间的数加上某个值,而是直接改变成某个值。直接拿上篇博客写的线段树区间修改模板改一下就可以了;
题目代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 100005
using namespace std;
struct node
{
int l,r;
int sum,tag;
}tree[maxn<<2];
void build(int k,int l,int r)
{
tree[k].l=l;tree[k].r=r;
tree[k].tag=0;
if(l==r)
{
tree[k].sum=1;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void change(int k)
{
if(tree[k].l!=tree[k].r)//把累加都换成赋值,因为是直接“变成”而不是“加上”
{
tree[k<<1].sum=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].tag;
tree[k<<1|1].sum=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].tag;
tree[k<<1].tag=tree[k].tag;
tree[k<<1|1].tag=tree[k].tag;
}
tree[k].tag=0;
}
void add(int k,int l,int r,int x)
{
if(tree[k].tag)
change(k);
tree[k].sum=(r-l+1)*x;
if(tree[k].l==l&&tree[k].r==r)
{
tree[k].tag=x;//注意这里直接赋值
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(l>=mid+1)
add(k<<1|1,l,r,x);
else if(r<=mid)
add(k<<1,l,r,x);
else
{
add(k<<1,l,mid,x);add(k<<1|1,mid+1,r,x);
}
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
int query(int k,int l,int r)
{
int res;
if(tree[k].tag)
change(k);
if(tree[k].l==tree[k].r)
return tree[k].sum;
int mid=(tree[k].l+tree[k].r)>>1;
if(l>=mid+1)
res=query(k<<1|1,l,r);
else if(r<=mid)
res=query(k<<1,l,r);
else
res=query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
return res;
}
int main(void)
{
int t,n,m;
int x,y,z;
int kase=0;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&x,&y,&z);
add(1,x,y,z);
}
printf("Case %d: The total value of the hook is %d.\n",++kase,query(1,1,n));
}
return 0;
}
呼呼