HDU-4027 Can you answer these queries? --线段树

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4027

题意及思路:

      有一排战舰,给出每个战舰的能力值,存在两种操作:第一种是把一定范围内所有战舰能力值开根号并向下取整,第二种是求一定区域内所有战舰能力值之和。如果我们暴力递归更新区间上的每一个点,会TLE(不要问我是怎么知道的)。我们可以稍微做一些优化。例如能力值0,1。它们开根号还是它们本身,不需要更新。我们可以增加一个标记tag。如果这个区间都是0或者1,我们就把tag标记为1。以后我们再次更新的时候如果区间tag为1,我们就不继续向下递归。

代码:

 1 #include <iostream>
 2 #include <cmath>
 3 #include <algorithm>
 4 #include <cstdio>
 5 #include <cstring>
 6 #define maxn 100000+5
 7 #define LL long long
 8 using namespace std;
 9 typedef struct node
10 {
11     LL a;
12     int tag;
13 }node;
14 node tree[maxn<<2];
15 void pushup(int rt)      //更新节点的和以及tag值
16 {
17     tree[rt].a=tree[rt<<1].a+tree[rt<<1|1].a;
18     if(tree[rt<<1].tag&&tree[rt<<1|1].tag)
19         tree[rt].tag=1;
20     return ;
21 }
22 int build(int l,int r,int rt)
23 {
24     if(l==r)
25     {
26         scanf("%lld",&tree[rt].a);
27         if(tree[rt].a==0||tree[rt].a==1)
28             tree[rt].tag=1;
29         return  1;
30     }
31     int m=(l+r)>>1;
32     build(l,m,rt<<1);
33     build(m+1,r,rt<<1|1);
34     pushup(rt);
35 }
36 void update(int L,int R,int l,int r,int rt)
37 {
38     if( L<=l  && r <= R&&tree[rt].tag==1)    //如果区间tag值为1,直接返回
39          return ;
40     if(l==r)
41     {
42         tree[rt].a=(LL)(sqrt(1.0*tree[rt].a));
43         if(tree[rt].a==1||tree[rt].a==0)
44             tree[rt].tag=1;
45         return ;
46     }
47     int m=(l+r)>>1;
48     if(L <= m)
49         update(L,R,l,m,rt<<1);
50     if(R >  m)
51         update(L,R,m+1,r,rt<<1|1);
52     pushup(rt);
53 }
54 LL query(int L,int R,int l,int r,int rt)
55 {
56     if(L <= l && r <= R)
57     {
58         return tree[rt].a;
59     }
60     int m=(l+r)>>1;
61     LL ans=0;
62     if(L <= m)
63         ans+=query(L,R,l,m,rt<<1);
64     if(R > m)
65         ans+=query(L,R,m+1,r,rt<<1|1);
66     return ans;
67 }
68 int main()
69 {
70     int n,jishu;
71     jishu=0;
72     while(scanf("%d",&n)!=EOF)
73     {
74         printf("Case #%d:\n",++jishu);
75         build(1,n,1);
76         int k;
77         scanf("%d",&k);
78         while(k--)
79         {
80             int c,a,b;
81             scanf("%d%d%d",&c,&a,&b);
82             if(a>b)
83                 swap(a,b);
84             if(c==0)
85                 update(a,b,1,n,1);
86             else
87                 cout<<query(a,b,1,n,1)<<endl;
88         }
89         cout<<endl;
90     }
91 }

 

转载于:https://www.cnblogs.com/blame/p/11369474.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值