HDU4027 线段树

题意:很多邪恶的战舰在战斗前排成一条线。我们的指挥官决定用我们的秘密武器消灭战舰。每艘战列舰都可以被标记为耐力的价值。对于我们的秘密武器的每一次攻击,都可以通过使其耐力达到其原始耐力值的平方根来降低战列舰连续部分的耐力。在我们秘密武器的一系列攻击中,指挥官想要评估武器的效果,所以他请求你的帮助。
你需要回答的问题是,连续部分的战舰线的耐力之和。

思路:因为是开方操作,所以不能乱搞区间操作,只能一个个点的更新。1的开方永远是1,所以当单点为1时特殊标记。如果在更新时遇到整段为1的区间,就可以跳过了。然后就是查数据。查数据应该不用解释了吧。。至于这题为什么不用for呢,自己脑补吧。

今天是618,买了个耳机本月就负债一百多了(感觉也太惨了吧)。然后要期末考试了,天天看高数有机化学都要吐了(大物还没开始自习,凉凉的感觉),今天实在看烦了就写道线段树冷静一下。然后输入的时候没有注意区间(输入u,v 可能u>v)然后疯狂RE (wc)。。。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=100010;
struct node{
 int left,right;
 bool flag;
 long long sum;
}tree[maxn*4];
long long  ans,a;
void pushdowm(int root)
{
 tree[root].sum=tree[root*2].sum+tree[root*2+1].sum;
 tree[root].flag=tree[root*2].flag&&tree[root*2+1].flag;
}
void build(int root,int left,int right)
{
 tree[root].left=left;
 tree[root].right=right;
 tree[root].flag=false;
 if(left==right)
 {
  cin>>a;
  tree[root].sum=a;
  if(a<=1)tree[root].flag=true;
  return;
 }
 int mid=(left+right)/2;
 build(root*2,left,mid);
 build(root*2+1,mid+1,right);
 pushdowm(root);
}
void update(int root,int left,int right)
{
 if(tree[root].flag)return;
 if(tree[root].left==left&&tree[root].right==right&&left==right)
 {
  tree[root].sum=(long long)sqrt(tree[root].sum*1.0);
  if(tree[root].sum<=1)tree[root].flag=true;
  return;
 }
 int mid=(tree[root].left+tree[root].right)/2;
 if(right<=mid)update(root*2,left,right);
 else if(left>mid)update(root*2+1,left,right);
 else {
  update(root*2,left,mid);
  update(root*2+1,mid+1,right);
 }
 pushdowm(root);
}
void que(int root,int left,int right)
{
 if(tree[root].left==left&&tree[root].right==right)
 {
  ans+=tree[root].sum;
  return;
 }
 int mid=(tree[root].left+tree[root].right)/2;
 if(right<=mid)que(root*2,left,right);
 else if(left>mid)que(root*2+1,left,right);
 else{
  que(root*2,left,mid);
  que(root*2+1,mid+1,right);
 }
}
int main()
{
 cin.sync_with_stdio(false);
 int n,m,u,v,q,cnt=0;
 while(cin>>n)
 {
  build(1,1,n);//在建树时输入 
  cin>>m;
  cout<<"Case #"<<++cnt<<":"<<endl;
  while(m--)
  {
   cin>>q>>u>>v;
   {
    if(u>v)swap(u,v);//数据可能V>U 不交换会爆 
    if(q==0)update(1,u,v);
    else 
       {
       ans=0;
                   que(1,u,v);
                   cout<<ans<<endl;
             }
   }
  }
  cout<<endl;
 }
 return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值