题意如下:
dota里面有一个hero名为Pudge,他有一个用链子连着的铁钩,一开始他的链子全是一块一块的铜块(价值为1)连接而制的,现在他可以选择任意长度(从i到j)然后对其进行改造,可以改成银块(价值为2),也可以改成金块(价值为3),然后在Q次改造后,要求你求出现在他的链子的总价值是多少!!!
这个题简化的话--->就是给出一个长度为n的数组,初始值全为1,然后在Q次改变指定长度的子数组的值后,再求出这个长度为n的数组的总值大小!
思路:使用线段树来做!百度线段树的地址:--->>>线段树
(说起来有点拗口,在本子上画一个线段树便一目了然了!)
一开始进行建树操作!然后再进行更新操作,即将一个K值赋值给数组里一个指定的区间,更新的时候需要注意下:如果一个节点所在的区间没有被num[i,j]这个区间完全包含,则需向下更新,同时还要将之前的更新还原给【以前需要更新但是没有进行更新的节点】(此时可以用flag[]数组来判断这个节点是否是之前需要更新但是却没有更新的节点);如果被完全包含了,则不用再继续向下更新了,直接将当前被包含区间进行一系列操作即可(赋值,标记)!
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=201314;
int sum[maxn<<2],flag[maxn<<2];
void s_s(int num)
{
sum[num]=sum[num<<1]+sum[num<<1|1];
}
void build(int l,int r,int chu,int num)
{
sum[num]=chu;//初始化更新,因为全部都是铜块!!!
flag[num]=0;//表明此时没有更新动作!
if(l==r)
return ;
int m=(r+l)>>1;
build(l,m,chu,num<<1);
build(m+1,r,chu,num<<1|1);
}
void gb(int num,int len)
{
if(flag[num])
{
flag[num<<1|1]=flag[num<<1]=flag[num];//向下传给子节点保存以前更新所改变的值!
sum[num<<1]=flag[num]*(len-(len>>1));
sum[num<<1|1]=flag[num]*(len>>1);
flag[num]=0;//然后将其状态改变为未更新!
}
}
void update(int i,int j,int l,int r,int k,int num)
{
if(i<=l&&j>=r)
{
sum[num]=k*(r-l+1);//表明当前区间已完全被包含于所需改变区间,此时直接赋值!
flag[num]=k;//更改状态!
return ;
}
gb(num,r-l+1);//向下给子节点传导父节点的状态!
int m=(l+r)/2;
if(i<=m)
update(i,j,l,m,k,num<<1);//如果此时所求区间有一部分在左子节点,则继续更新
if(j>m)
update(i,j,m+1,r,k,num<<1|1);//如果此时所求区间有一部分在右子节点,则继续更新
sum[num]=sum[num<<1]+sum[num<<1|1];//最后再次求所求区间的求和!
}
int main()
{
int T;
cin>>T;
for(int ji=1; ji<=T; ji++)
{
int n,Q;
cin>>n;
build(1,n,1,1);
cin>>Q;
while(Q--)
{
int x,y,z;
cin>>x>>y>>z;
update(x,y,1,n,z,1);
//for(int i=1; i<20; i++)
//if(sum[i])
// cout<<sum[i]<<",";
//cout<<"--->"<<sum[1]<<endl;
}
printf("Case %d: The total value of the hook is %d.\n",ji,sum[1]);
}
return 0;
}
hdu-1698-Just a Hook.,布布扣,bubuko.com
原文地址:http://blog.csdn.net/u014004096/article/details/38140597