HDU-4027 Can you answer these queries?(线段树区间开方)

时间:2019-08-25
本文章向大家介绍HDU-4027 Can you answer these queries?(线段树区间开方),主要包括HDU-4027 Can you answer these queries?(线段树区间开方)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)

Problem Description

A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the battleships. Each of the battleships can be marked a value of endurance. For every attack of our secret weapon, it could decrease the endurance of a consecutive part of battleships by make their endurance to the square root of it original value of endurance. During the series of attack of our secret weapon, the commander wants to evaluate the effect of the weapon, so he asks you for help. 
You are asked to answer the queries that the sum of the endurance of a consecutive part of the battleship line. 
Notice that the square root operation should be rounded down to integer.

Input

The input contains several test cases, terminated by EOF. 
  For each test case, the first line contains a single integer N, denoting there are N battleships of evil in a line. (1 <= N <= 100000) 
  The second line contains N integers Ei, indicating the endurance value of each battleship from the beginning of the line to the end. You can assume that the sum of all endurance value is less than 2 63
  The next line contains an integer M, denoting the number of actions and queries. (1 <= M <= 100000) 
  For the following M lines, each line contains three integers T, X and Y. The T=0 denoting the action of the secret weapon, which will decrease the endurance value of the battleships between the X-th and Y-th battleship, inclusive. The T=1 denoting the query of the commander which ask for the sum of the endurance value of the battleship between X-th and Y-th, inclusive. 

Output

For each test case, print the case number at the first line. Then print one line for each query. And remember follow a blank line after each test case.

Sample Input

10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8

Sample Output

Case #1:
19
7
6
题目大意:
一共有n个数,m个操作,操作分两种:0 x y表示将区间[x,y]的数开方,1 x y表示查询区间[x,y]的和。

解题思路:

很明显的线段树

很容易想到区间更新的lazy思想,但是这道题的更新并不是简单的加减乘除,而是开方。但是开方的话我们无法通过延迟更新来减少时间复杂度,也就是说lazy思想在这里并不是太试用。

那么我们想一想算术平方根,sqrt(1)=1,且考虑到数据范围为2的63次方,也就是说这个数最多只能开7次平方,因为接下来如何再开方都是1了。

所以我们就可以从这点入手,当更新时我们不延迟更新了,需要我们判断一下是否需要更新。

如果在这个区间内SegTree[rt].sum = SegTree[rt].r-SegTree[rt].l+1(就是区间内有点都为1)很明显这个时候不用更新区间,那就直接return。

如果这个区间可以更新,那就直接更新这个区间。所以每次更新都更新到叶子结点,维护区间和就行了。

 

除此之外,这题也有不少的坑点:

1:要区分好那些数据是long long,那些是int

2:注意每个样例后都要输出一个空行

3:注意输入x,y后要检查是否x<=y,如果x>y,要交换x和y(最坑的点,做过那么多的区间查询,这是我遇见的第一个还设置这种坑的,有意思么。。。)

代码如下:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <string>
  5 #include <math.h>
  6 #include <algorithm>
  7 #include <vector>
  8 #include <queue>
  9 #include <set>
 10 #include <map>
 11 #include <math.h>
 12 const int INF=0x3f3f3f3f;
 13 typedef long long LL;
 14 const int mod=1e9+7;
 15 //const double PI=acos(-1);
 16 const int maxn=1e5+10;
 17 using namespace std;
 18 //ios::sync_with_stdio(false);
 19 //    cin.tie(NULL);
 20 
 21 int n,m;
 22 struct node
 23 {
 24     int l;
 25     int r;
 26     LL sum;
 27 }SegTree[maxn<<2];
 28 
 29 void PushUp(int rt)
 30 {
 31     SegTree[rt].sum=SegTree[rt<<1].sum+SegTree[rt<<1|1].sum;
 32 }
 33 
 34 void Build(int l,int r,int rt)
 35 {
 36     SegTree[rt].l=l;
 37     SegTree[rt].r=r;
 38     if(l==r)
 39     {
 40         scanf("%lld",&SegTree[rt].sum);
 41         return;
 42     }
 43     int mid=(l+r)>>1;
 44     Build(l,mid,rt<<1);
 45     Build(mid+1,r,rt<<1|1);
 46     PushUp(rt);
 47 }
 48 
 49 void Update(int L,int R,int rt)
 50 {
 51     int l=SegTree[rt].l;
 52     int r=SegTree[rt].r;
 53     if(L<=l&&R>=r)
 54     {
 55         if(SegTree[rt].sum==SegTree[rt].r-SegTree[rt].l+1)//说明该区间全是1,没必要开方
 56             return ;    
 57     }
 58     if(l==r)//该区间不为1 
 59     {
 60         SegTree[rt].sum=(LL)sqrt(SegTree[rt].sum*1.0);
 61         return ;
 62     }
 63     int mid=(l+r)>>1;
 64     if(L<=mid)
 65         Update(L,R,rt<<1);
 66     if(R>mid)
 67         Update(L,R,rt<<1|1);
 68     PushUp(rt);
 69 }
 70 
 71 LL Query(int L,int R,int rt)
 72 {
 73     int l=SegTree[rt].l;
 74     int r=SegTree[rt].r;
 75     if(L<=l&&R>=r)
 76     {
 77         return SegTree[rt].sum;
 78     }
 79     LL SUM=0;
 80     int mid=(l+r)>>1;
 81     if(L<=mid)
 82         SUM+=Query(L,R,rt<<1);
 83     if(R>mid)
 84         SUM+=Query(L,R,rt<<1|1);
 85     return SUM;
 86 }
 87 
 88 int main()
 89 {
 90     //freopen("sample.txt","r",stdin);
 91     int num=1;
 92     while(~scanf("%d",&n))
 93     {
 94         printf("Case #%d:\n",num++);
 95         Build(1,n,1);
 96         scanf("%d",&m);
 97         for(int i=1;i<=m;i++)
 98         {
 99             int f,x,y;
100             scanf("%d %d %d",&f,&x,&y);
101             if(x>y)//坑点 
102                 swap(x,y);
103             if(f==0)
104             {
105                 Update(x,y,1);
106             }
107             else if(f==1)
108             {
109                 printf("%lld\n",Query(x,y,1));
110             }
111         }
112         printf("\n");//坑点 
113     }
114     return 0;
115 }

原文地址:https://www.cnblogs.com/jiamian/p/11408944.html