题意如下:
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