BZOJ 3211: 花神游历各国( 线段树 )

线段树...区间开方...明显是要处理到叶节点的

之前在CF做过道区间取模...差不多, 只有开方, 那么每个数开方次数也是有限的(0,1时就会停止), 最大的数10^9开方10+次也就不会动了.那么我们线段树多记个max就可以少掉很多不必要的操作

--------------------------------------------------------------------------------------------

#include<cstdio>

#include<cstring>

#include<cmath>

#include<algorithm>

#include<iostream>

#define rep(i, n) for(int i = 0; i < n; i++)

#define M(l, r) (((l) + (r)) >> 1)

#define clr(x, c) memset(x, c, sizeof(x))

using namespace std;

typedef long long ll;

const int maxn = 100009;

struct Node {

Node *l, *r;

int v, mx;

ll sum;

Node():mx(0) {

l = r = NULL;

}

inline void update() {

if(l) {

mx = max(l->mx, r->mx);

sum = l->sum + r->sum;

} else

sum = mx = v;

}

} pool[maxn << 1], *pt = pool, *root;

int L, R, n, seq[maxn];

void build(Node* t, int l, int r) {

if(r > l) {

int m = M(l, r);

build(t->l = pt++, l, m);

build(t->r = pt++, m + 1, r);

} else

t->v = seq[l];

t->update();

}

void modify(Node* t, int l, int r) {

if(t->mx <= 1) return;

if(l == r)

t->v = floor(sqrt(t->v));

else {

int m = M(l, r);

if(L <= m) modify(t->l, l, m);

if(m < R) modify(t->r, m + 1, r);

}

t->update();

}

ll query(Node* t, int l, int r) {

if(L <= l && r <= R)

return t->sum;

int m = M(l, r);

return (L <= m ? query(t->l, l, m) : 0 ) + (m < R ? query(t->r, m + 1, r) : 0);

}

int main() {

// freopen("test.in", "r", stdin);

cin >> n;

for(int i = 1; i <= n; i++)

scanf("%d", seq + i);

build(root = pt++, 1, n);

int m, op;

cin >> m;

while(m--) {

scanf("%d%d%d", &op, &L, &R);

if(op == 1)

printf("%lld\n", query(root, 1, n));

else

modify(root, 1, n);

}

return 0;

}

--------------------------------------------------------------------------------------------

3211: 花神游历各国

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 1414  Solved: 546
[Submit][Status][Discuss]

Description

Input

Output

每次x=1时,每行一个整数,表示这次旅行的开心度

Sample Input

4

1 100 5 5

5

1 1 2

2 1 2

1 1 2

2 2 3

1 1 4

Sample Output

101

11

11

HINT

对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9

Source

SPOJ2713 gss4 数据已加强

时间: 2024-10-15 01:38:30

BZOJ 3211: 花神游历各国( 线段树 )的相关文章

BZOJ 3211 花神游历各国 线段树题解

BZOJ 3211 花神游历各国 线段树题解 3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2551  Solved: 946[Submit][Status][Discuss] Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4 Sample Output 101

BZOJ 3211 花神游历各国 (树状数组+并查集)

题解:首先,单点修改求区间和可以用树状数组实现,因为开平方很耗时间,所以在这个方面可以优化,我们知道,开平方开几次之后数字就会等于1 ,所以,用数组记录下一个应该开的数,每次直接跳到下一个不是1的数字进行开平方,至于这个数组,可以用并查集维护. #include <cstdio> #include <cmath> #include <iostream> using namespace std; typedef long long LL; LL c[100005]; in

bzoj3211花神游历各国 线段树

3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 4252  Solved: 1547[Submit][Status][Discuss] Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 41 100 5 551 1 22 1 21 1 22 2 31 1 4 Sample Output 1011111 HINT 对于100%的数据, n ≤ 1000

BZOJ 3211 花神游历各国 树状数组(线段树)+优化

题意:给你一段区间,然后每个点的初始值都告诉你,现有两种操作,一种是给你一个小区间的左右端点,之后把这个区间内的所有值都开根号,另一种就是区间求值. 方法:树状数组维护求和,巧妙开根号.(线段树) 解析:这道是某次考试考的题- -.当时也没想到快的开根号方法,暴力开根号好像70分吧. 首先要明确一个事情:被开根号的数最大是109,而109开几次会开到1呢?用计算器算一下发现5次就将这个最大的数开到1了,而1开根号怎么开都是1,所以如果再对其进行开根号操作,仅仅是无用的浪费时间了.所以怎么维护这种

BZOJ 3211 花神游历各国 树状数组+并查集

题目大意:花神对每一个国家有一个喜爱程度,有的时候他会对连续的一段国家进行访问,求他的喜爱程度的和:有的时候他会对连续的一段国家产生厌恶,喜爱程度变成sqrt(x)下取整. 思路:乍一看好像是RMQ问题,用线段树就可以水过,但是开根号的标记怎么下传?这是一个严重的问题,所以我们要换一个思路. 注意到开根号有一个有趣的性质:sqrt(1) = 1,sqrt(0) = 0,而且所有的数字经过有限次的开根号运算都会变成1.这个性质就很好了.我们对每一个点暴力开根号,然后当这个店的点权变成1的时候就打一

bzoj 3211 花神游历各国

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3211 题解: 线段树区间开根号操作,目前只能通过单点修改来实现,但是发现:一个小于109的数开过5次根号后向下取整就会变成1 所以在每一次开根号操作后判断,如果这个数已经开到1甚至0,则线段树当前结点flag值设为true,以后再访问该结点时不再操作 父结点的flag值可以由两个儿子的flag值按位与得到 只有开根号操作的话代码还是比较简单的 1 #include<cstdio> 2

[BZOJ 3211]花神游历各国(并查集+树状数组)

Description Solution 树状数组单点修改区间查询 我们知道一个数n最多修改loglogn次就会变为1 并查集维护每个数右边第一个不为1的位置 #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<cmath> #define MAXN 100005 using namespace std; typedef long lon

3211: 花神游历各国

直接写题解吧... 题目这么长,其实就是2个操作: 1.询问L,R中的各个数之和 2.将L,R中的每个数x,将x修x1/2,向下取整.. 我们其实可以发现1000000000中的数修改不了几次就会变成1 那么直接暴力修改,若一段区间内的数全部<=1也就不用再改下去了.. #include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> using namespace st

【线段树】【bzoj 3211】花神游历各国

3211: 花神游历各国 Time Limit: 5 Sec Memory Limit: 128 MB Submit: 1508 Solved: 573 Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4 Sample Output 101 11 11 HINT 对于100%的数据, n ≤ 100000,m≤200000 ,data[