题意:看到题意和配图,我也是醉了。。。DotA屠夫的钩,是一节一节组成的,有n节,初始每节的长度是1。屠夫可以改变一个区间内每节的长度为1,2,3。。。问q次改变以后,总长度是多少。
思路:线段树(区间更新)。区间保存的是对应钩子区间每节的长度,如果区间内长度不一,则这个区间是无效的,需要考察这个区间的子区间,直到有一个统一的长度。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
using namespace std;
struct node{
int l;
int r;
int val;
bool flag;
};
node tree[400010];
void build_tree(int n,int l,int r){
tree[n].l=l; tree[n].r=r; tree[n].val=1; tree[n].flag=1;
if(l==r)return;
int mid=(l+r)/2;
build_tree(n*2,l,mid);
build_tree(n*2+1,mid+1,r);
}
void update(int n,int l,int r,int v){
if(tree[n].l==l&&tree[n].r==r){
tree[n].val=v; tree[n].flag=1;
return;//应用了lazy思想,暂时不更新子区间。
}
int mid=(tree[n].l+tree[n].r)/2;
if(tree[n].flag){//这个时候不得不更新子区间了。
update(n*2,tree[n].l,mid,tree[n].val);
update(n*2+1,mid+1,tree[n].r,tree[n].val);
}
if(r<=mid){
update(n*2,l,r,v);
}else{
if(l<=mid){//跨区间
update(n*2,l,mid,v);
update(n*2+1,mid+1,r,v);
}else{
update(n*2+1,l,r,v);
}
}
tree[n].flag=0;
}
int sum(int n){
if(tree[n].flag||(tree[n].l==tree[n].r)){
int tmp=tree[n].val;
return (tree[n].r-tree[n].l+1)*tree[n].val;
}
return sum(n*2)+sum(n*2+1);
}
int main(){
int t;
cin>>t;
int cas=0;
while(t--){
cas++;
int n,q;
cin>>n>>q;
build_tree(1,1,n);
while(q--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
update(1,a,b,c);
}
printf("Case %d: The total value of the hook is %d.\n",cas,sum(1));
}
return 0;
}
本文介绍了一道关于DotA中屠夫钩子长度变化的编程题,使用线段树实现区间更新来求解钩子总长度。通过懒惰传播优化算法效率。
408

被折叠的 条评论
为什么被折叠?



