HDU 6315 Naive Operations【线段树】(2018 MUTC 2)

Naive Operations

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


 

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

题目大意:

给你一个静态不变的数组b,和一个初始化为0的数组a,大小都为n(假设数组下标从1~n)。然后有m次操作,add(往a数组的下标从left~right各加上1)或者query(求left~right的ai/bi总和,ai/bi是整除)

解法:

如果只是最普通的线段数模板,每次都更新子区间,更新总和,是会TLE的。你要理解这道题的意思,并不是每次增加ai的值,ai/bi都会改变,只有当ai是bi倍数关系的时候,ai/bi的值才会改变,所以我们如果每次都维护ai/bi这个值得话,会很浪费时间。

我们应当去维护ai的最大值和bi的最小值之间的关系,这样我们就不用每次的去更新ai/bi的值,而是判断ai和bi的大小关系,就可以得出总和的值是否要改变。

附上AC代码:

#include <bits/stdc++.h>
#define MAXN 100005
using namespace std;

int b[MAXN];

struct KNIGHT{
	int left;
	int right;
	int sum;
	int lazy;//懒惰数组,只有需要的时候才继续往下更新,节省时间 
	int maxA;
	int minB;
}p[MAXN<<2];

void pushup(int root){
	p[root].maxA = max(p[root<<1].maxA , p[root<<1|1].maxA);
	p[root].minB = min(p[root<<1].minB , p[root<<1|1].minB);
	p[root].sum = p[root<<1].sum + p[root<<1|1].sum;
}

void build(int root ,int left ,int right){
	p[root].left = left;
	p[root].right = right;
	p[root].lazy = p[root].sum = 0;
	
	if(left == right){
		p[root].maxA = 0;
		p[root].minB = b[left];
		return;
	}
	int mid = (left+right) >> 1;
	build(root<<1 , left, mid);
	build(root<<1|1 ,mid+1 ,right);
	pushup(root);
}
void update(int root){
	p[root<<1].lazy += p[root].lazy ;
	p[root<<1|1].lazy += p[root].lazy;
	p[root<<1].maxA += p[root].lazy ;
	p[root<<1|1].maxA += p[root].lazy ;
	p[root].lazy = 0;
}
void add(int root ,int left , int right){
	if(left > right)
		return;
	if(left <= p[root].left && p[root].right <= right){
		p[root].maxA ++ ;
		if(p[root].minB <= p[root].maxA && p[root].left == p[root].right){
			p[root].sum ++;
			p[root].minB += b[p[root].left];
			return;
		}
		if(p[root].minB > p[root].maxA){
			p[root].lazy ++ ;
			return;
		}
	}
	if(p[root].lazy)
		update(root);
	int mid = (p[root].left+p[root].right) >> 1 ;
	if(mid >= right){
		add(root << 1, left, right);
	}else if(mid < left){
		add(root << 1 | 1 , left, right);
	}else{
		add(root << 1,left , mid);
		add(root << 1 | 1, mid+1, right);
	}
	pushup(root);
}

int query(int root, int left , int right){
	if(left <= p[root].left && p[root].right <= right)
		return p[root].sum ;
	int mid = (p[root].left + p[root].right) >> 1 ;
	if(mid >= right){
		return query(root << 1, left, right);
	}else if(mid < left){
		return query(root <<1 | 1, left, right);
	}else{
		return query(root << 1, left, mid) + query(root << 1 | 1, mid + 1, right);
	}
}

int main(){
	int n,m,l,r;
	char s[10];
	while(scanf("%d%d" , &n, &m) != EOF){
		for(int i = 1;i <= n; i++)
			scanf("%d", b+i);
		build(1 ,1 ,n );
		for(int i = 1;i <= m; i++){
			scanf("%s %d %d", s, &l, &r);
			if(strcmp(s,"add") == 0)
				add(1 , l , r);
			else
				printf("%d\n", query(1,l,r));
		}
	}
}
发布了22 篇原创文章 · 获赞 19 · 访问量 3552

猜你喜欢

转载自blog.csdn.net/KnightHONG/article/details/81222244