HDU 6315 Naive Operations(线段树)

Naive Operations

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/Others)
Total Submission(s): 1659    Accepted Submission(s): 709


 

Problem Description

In a galaxy far, far away, there are two integer sequence a and b of length n.
b is a static permutation of 1 to n. Initially a is filled with zeroes.
There are two kind of operations:
1. add l r: add one for al,al+1...ar
2. query l r: query ∑ri=l⌊ai/bi⌋

 

Input

There are multiple test cases, please read till the end of input file.
For each test case, in the first line, two integers n,q, representing the length of a,b and the number of queries.
In the second line, n integers separated by spaces, representing permutation b.
In the following q lines, each line is either in the form 'add l r' or 'query l r', representing an operation.
1≤n,q≤100000, 1≤l≤r≤n, there're no more than 5 test cases.
 

Output

Output the answer for each 'query', each one line.

Sample Input

5 12

1 5 2 4 3

add 1 4

query 1 4

add 2 5

query 2 5

add 3 5

query 1 5

add 2 4

query 1 4

add 2 5

query 2 5

add 2 2

query 1 5

 

 

Sample Output

1

1

2

4

4

6 

 

Source

2018 Multi-University Training Contest 2

 

 

Recommend

chendu   |   We have carefully selected several similar problems for you:  6318 6317 6316 6315 6314 

 【思路】

多校第二场,应该开出来的第三题,很遗憾没能做出来,思路十分厉害,补记之。

不是每一次更新都要去对应的点来确认是否加一的,只需要在每个点被修改bi次时才需要加一。鉴于b_{i}序列是一个1到n的排列,当满打满算时分子最终为q,整个序列就成了调和级数,因此用线段树维护,实质在叶子节点的更新次数也是对数级别的。

线段树维护\frac{a_{i}}{b_{i}}的区间和sum与每个节点还有几次才加一这个数字的区间最小值min,每次更新就区间减一,当区间被减到0时,就dfs到它的叶子节点把他的sum加一,再把min改为b_{i}

 

【代码】

//******************************************************************************
// File Name: 1007.cpp
// Author: Shili_Xu
// E-Mail: shili_xu@qq.com
// Created Time: 2018年07月26日 星期四 14时00分47秒
//******************************************************************************

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int MAXN = 101000;

struct segment {
	int sum, min, flag;
};

int n, q;
int b[MAXN];
segment tree[MAXN << 2];

void push_down(int rt)
{
	if (tree[rt].flag) {
		tree[rt << 1].min += tree[rt].flag;
		tree[rt << 1].flag += tree[rt].flag;
		tree[rt << 1 | 1].min += tree[rt].flag;
		tree[rt << 1 | 1].flag += tree[rt].flag;
		tree[rt].flag = 0;
	}
}

void update(int rt)
{
	tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
	tree[rt].min = min(tree[rt << 1].min, tree[rt << 1 | 1].min);
}

void build(int left, int right, int rt)
{
	tree[rt].flag = 0;
	if (left == right) {
		tree[rt].min = b[left];
		tree[rt].sum = 0;
		return;
	}
	int mid = (left + right) >> 1;
	build(left, mid, rt << 1);
	build(mid + 1, right, rt << 1 | 1);
	update(rt);
}

void modify(int l, int r, int x, int left, int right, int rt)
{
	int mid = (left + right) >> 1;
	if (l <= left && right <= r) {
		tree[rt].min += x;
		tree[rt].flag += x;
		if (!tree[rt].min) {
			if (left == right) {
				tree[rt].sum++;
				tree[rt].min = b[left];
				return;
			}
			push_down(rt);
			if (!tree[rt << 1].min) modify(l, r, 0, left, mid, rt << 1);
			if (!tree[rt << 1 | 1].min) modify(l, r, 0, mid + 1, right, rt << 1 | 1);
			update(rt);
		}
		return;
	}
	push_down(rt);
	if (l <= mid) modify(l, r, x, left, mid, rt << 1);
	if (r >= mid + 1) modify(l, r, x, mid + 1, right, rt << 1 | 1);
	update(rt);
}

int query(int l, int r, int left, int right, int rt)
{
	if (l <= left && right <= r) return tree[rt].sum;
	push_down(rt);
	int mid = (left + right) >> 1;
	int ans = 0;
	if (l <= mid) ans += query(l, r, left, mid, rt << 1);
	if (r >= mid + 1) ans += query(l, r, mid + 1, right, rt << 1 | 1);
	return ans;
}

int main()
{
	while (scanf("%d %d", &n, &q) == 2) {
		for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
		build(1, n, 1);
		while (q--) {
			char mes[20];
			int l, r;
			scanf("%s %d %d", mes, &l, &r);
			if (mes[0] == 'a')
				modify(l, r, -1, 1, n, 1);
			else {
				int ans = query(l, r, 1, n, 1);
				printf("%d\n", ans);
			}
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值