kb-07线段树-08--区间开根

  1 /*
  2    hdu-4027
  3    题目:区间开根求和查询;
  4    因为是开根,所以要更新的话就要更新到叶子节点。如果区间里全是1或是0的话就步用继续更新了,查询的时候正常查询;
  5  */
  6 #include<iostream>
  7 #include<cstring>
  8 #include<cstdio>
  9 #include<cmath>
 10 #define ll long long
 11 using namespace std;
 12 struct Node
 13 {
 14     int l,r;
 15     ll value;
 16     int add;
 17 }tr[400008]={0};
 18 ll n,m,a[100005]={0};
 19 ll ans=0;
 20 void Pushup(int rt)
 21 {
 22     int lson=rt<<1;
 23     int rson=rt<<1|1;
 24     tr[rt].value=tr[lson].value+tr[rson].value;
 25     if(tr[lson].add==1||tr[rson].add==1)
 26         tr[rt].add=1;
 27     else
 28         tr[rt].add=0;
 29 }
 30 void build(int rt,int l,int r)
 31 {
 32     tr[rt].l=l;
 33     tr[rt].r=r;
 34     tr[rt].add=1;
 35     if(l==r)
 36     {
 37         tr[rt].value=a[l];
 38         return ;
 39     }
 40     int mid=(l+r)/2;
 41     build(rt<<1,l,mid);
 42     build(rt<<1|1,mid+1,r);
 43     Pushup(rt);
 44 }
 45 void Update(int rt,int l,int r)
 46 {
 47     if(tr[rt].add==0)//如果区间全是1或0就不更新;
 48         return;
 49     if(tr[rt].l==tr[rt].r&&l==r)//深入到叶子节点开根号;
 50     {
 51         tr[rt].value=(int)sqrt((double)tr[rt].value);
 52         if(tr[rt].value==1||tr[rt].value==0)
 53             tr[rt].add=0;
 54         return ;
 55     }//没有要pusdown的所以没有pushdown
 56     if(l<=tr[rt<<1].r)
 57     {
 58         if(r<=tr[rt<<1].r)
 59             Update(rt<<1,l,r);
 60         else
 61             Update(rt<<1,l,tr[rt<<1].r);
 62     }
 63     if(r>=tr[rt<<1|1].l)
 64     {
 65         if(l>=tr[rt<<1|1].l)
 66             Update(rt<<1|1,l,r);
 67         else
 68             Update(rt<<1|1,tr[rt<<1|1].l,r);
 69     }
 70     Pushup(rt);
 71 }
 72 void Query(int rt,int l,int r)
 73 {
 74     if(tr[rt].l==l&&tr[rt].r==r)
 75     {
 76         ans+=tr[rt].value;
 77         return ;
 78     }
 79     if(l<=tr[rt<<1].r)
 80     {
 81         if(r<=tr[rt<<1].r)
 82             Query(rt<<1,l,r);
 83         else
 84             Query(rt<<1,l,tr[rt<<1].r);
 85     }
 86     if(r>=tr[rt<<1|1].l)
 87     {
 88         if(l>=tr[rt<<1|1].l)
 89             Query(rt<<1|1,l,r);
 90         else
 91             Query(rt<<1|1,tr[rt<<1|1].l,r);
 92     }
 93 }
 94 int main()
 95 {
 96     int k=1;
 97     while(scanf("%lld",&n)!=EOF)
 98     {
 99         printf("Case #%d:\n",k++);
100         memset(a,0,sizeof(a));
101         memset(tr,0,sizeof(tr));
102         for(int i=1;i<=n;i++)
103         {
104             scanf("%lld",&a[i]);
105         }
106         build(1,1,n);
107         scanf("%lld",&m);
108         for(int i=0;i<m;i++)
109         {
110             int x,l,r;
111             scanf("%d%d%d",&x,&l,&r);
112             if(l>r)//输入有坑;
113                 swap(l,r);
114             if(x==0)
115             {
116                 Update(1,l,r);
117             }
118             else
119             {
120                 ans=0;
121                 Query(1,l,r);
122                 printf("%lld\n",ans);
123             }
124         }
125         printf("\n");
126     }
127     return 0;
128 }
时间: 2024-10-03 14:14:51

kb-07线段树-08--区间开根的相关文章

刷题向》关于线段树的区间开根号 BZOJ3211

这是一道关于线段树的区间开根号的裸题,没什么好讲的. 值得注意的是,因为有区间开根号的性质,所以我们每一次更改操作只能把更改区间所覆盖的所有元素全部查找,当然你直接找效率明显爆炸... 能够注意到,指数级别的操作一次更改的数字都很大,而题目的数字最大是10的9次,所以可以注意到的是当一个区间更新6遍以后就失去更新的意义了,因为当你更改次数超过6次所有非负整数数字就全部会化为1.所以可以在每一个节点上加一个类似于LAZY标记的东西,记录开根号次数,以便节约跟新时间. 贴出题目&代码 Descrip

算法模板——线段树5(区间开根+区间求和)

实现功能——1:区间开根:2:区间求和(此模板以BZOJ3038为例) 作为一个非常规的线段树操作,其tag也比较特殊呵呵哒 1 var 2 i,j,k,l,m,n:longint; 3 a,b:array[0..500000] of int64; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end; 8 function min(x,y:longint):long

[BZOJ3211]花神游历各国(线段树+区间开根)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3211 分析: 区间开根是没法区间合并的. 但是注意到10^9开根开个5次就变成1了…… 于是只要在每个区间额外维护个值b,b=1表示这段全部都是1了,不用修改了,b=2表示这段没有全部是1,还要修改 然后这样就行了

CodeForces 52C Circular RMQ(区间循环线段树,区间更新,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://codeforces.com/problemset/problem/52/C You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segm

HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)

题目 线段树 简单题意: 区间(单点?)更新,区间求和 更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都是开平方,同一个数更新有限次数就一直是1了,所以可以这样优化 #include <stdio.h> #include<math.h> #define N 100010 #define LL __int64 #define lson l,m,rt<<1 #define rson

FZU Problem 2171 防守阵地 II (线段树,区间更新)

 Problem 2171 防守阵地 II Accept: 143    Submit: 565Time Limit: 3000 mSec    Memory Limit : 32768 KB  Problem Description 部队中总共有N个士兵,每个士兵有各自的能力指数Xi,在一次演练中,指挥部确定了M个需要防守的地点,指挥部将选择M个士兵依次进入指定地点进行防守任务,获得的参考指数即为M个士兵的能力之和.随着时间的推移,指挥部将下达Q个指令来替换M个进行防守的士兵们,每个参加完防守

线段树为什么要开4倍空间

线段树为什么要开4倍空间 Creation Time: 19 March 2014Last Modified: 2014-03-23 01:01:26 scinart 最近在看<具体数学>,这篇当做是一个练习吧. 假设我们用一个数组来头轻脚重地存储一个线段树,根节点是1,孩子节点分别是2n, 2n+1, 那么,设线段长为L(即[1..L+1)) 设树的高度为H,对H,有: H(L)={1,L = 11+H(⌈L2⌉),L > 1 这是一个很简单的递归式,并用公式3.11逐次代换,就等到

poj 2777 线段树的区间更新

Count Color Time Limit: 1000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description Chosen Problem Solving and Program design as an optional course, you are required to solve al

Super Mario(线段树离线区间k值)

以前见过这题,没做出来,知道是离线处理,这次仔细想了下, 首先把出现的高度都map离散化一下,以离散化出来的数目g建树,把每个位置都开俩个vector,一个存以这个位置为L的询问,一个存以这个位置为R的询问. 然后从1-g 进行更新,假如当前i是以第j个区间的开始位置,那么这时就可以询问一下<=p[j].h的个数s,显然这时第J个区间多加的,需要减掉,p[j].sum-=s; 然后更新第i个数,update(a[i],1,g,1);再找到某第k区间是以i结尾的,那么依旧询问一下,得出s,p[k]