1 10 2 1 5 2 5 9 3
Case 1: The total value of the hook is 24.
2008 “Sunline Cup” National Invitational Contest
题意: 给定你1~N的区间,有Q次询问,将x到y的全部变为z。最后输出其总和(最开始默认每个区间的值均为1)
输入:数据组数t,询问次数q,区间长度n。接着有q次询问,分别输入x,y,z。
输出:q次操作后,整个区间的总和。
解法: 线段树的区间更新。
对于线段树的区间修改,当我们找到需要更新的区间后,更新当前区间,而后只记录下更新状态,而不在向下更新。当需要修改更新后区间的成员时,就将记录的更新状态向下更新(注意清除之前更新标记)。
体会:从早上写到中午两点多,当AC时的时候真令人兴奋。虽然对算法都有个大致的了解,但具体写出来的时候各种坑,各种手残~~~~AC万岁
AC 代码:
//#define zhouV
#include<string.h>
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long int
#define maxn 1000010
struct ss
{
int l,r,sum,org;
}tr[3*maxn];
void pushup(int id)//向上更新
{
tr[id].sum=tr[id*2].sum+tr[id*2+1].sum;
}
void pushdown(int id)//向下更新
{
int temp=id*2;
if(tr[id].org)
{
tr[temp].org=tr[id].org;
tr[temp+1].org=tr[id].org;
tr[temp].sum=tr[id].org*(tr[temp].r-tr[temp].l+1);
tr[temp+1].sum=tr[id].org*(tr[temp+1].r-tr[temp+1].l+1);
tr[id].org=0;//清楚标记
}
}
void build(int id,int l,int r)//建树
{
tr[id].l=l;
tr[id].r=r;
tr[id].org=0;
if(l==r)
{
tr[id].sum=1;
return;
}
int mid=(l+r)>>1;
int temp=id<<1;
build(temp,l,mid);
build(temp+1,mid+1,r);
pushup(id);
}
void updata(int id,int l,int r,int v)//操作
{
if(l>tr[id].r||r<tr[id].l) return ;
if(tr[id].l>=l&&tr[id].r<=r)
{
tr[id].sum=v*(tr[id].r-tr[id].l+1);
tr[id].org=v;
return;
}
int mid=(tr[id].l+tr[id].r)>>1;
int temp=id<<1;
pushdown(id);
if(mid>=r) updata(temp,l,r,v);
else if(mid<l) updata(temp+1,l,r,v);
else if(mid>=l&&mid<r)
{
updata(temp,l,r,v);
updata(temp+1,l,r,v);
}
pushup(id);
}
int main()
{
#ifdef zhouV
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
int t,n,q;
scanf("%d",&t);
for(int j=1;j<=t;j++)
{
int x,y,z;
scanf("%d%d",&n,&q);
build(1,1,n);
while(q--)
{
scanf("%d%d%d",&x,&y,&z);
updata(1,x,y,z);
#ifdef zhouV
printf("%d\n",tr[1].sum);
#endif
}
printf("Case %d: The total value of the hook is %d.\n",j,tr[1].sum);
}
}
测试样例:
1
10
10
4 6 2
1 10 1
1 5 2
1 10 1
1 5 2
5 10 2
1 10 1
1 3 2
3 5 2
3 5 3
OUTPUT:
每一次操作后的值
13
10
15
10
15
20
10
13
15
18
ans:
Case 1: The total value of the hook is 18.