2018 Multi-University Training Contest 2 Naive Operations -HDU 6315(线段树)

Naive Operations

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


 

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

2

4

4

6

Source

2018 Multi-University Training Contest 2

题目大意:给定两个数组分别为a,b,其中a初始全为0,输入n个数作为b数组的元素,输入m次操作次数,其中操作有两种:

add(first,last):在a数组中索引为第 first 到 last 的的数都加一

query(first,last):输出(a数组中索引为第 first 到 last 的的数分别除以b数组中索引为第 first 到 last 的的数的和)

解题思路:建立一个线段树,分别保存其a数组和b数组,并维护a数组的最大值,以及维护b数组的最小值,当最小值大于最大  值时,就直接跳过(对query不影响),一直到最小值大于等于最大值时,输出的ans+1,并且使其最小值加上原来的值(线段树用lazy数组进行优化)。

代码如下:

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
struct node{
	int l,r,max,min,lazy,sum; /*max表示当前区间下a数组的最大值,min表示当前区间下b数组的最小 
                                值,sum表示当前区间ai/bi的和 */
}tree[MAXN<<2];
int be[MAXN];
void update(int i){ //维护其最大值和最小值 
	tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
	tree[i].max=max(tree[i<<1].max,tree[i<<1|1].max);
	tree[i].min=min(tree[i<<1].min,tree[i<<1|1].min);
}
void build(int l,int r,int i){ //建立线段树 
	tree[i].l=l;
	tree[i].r=r;
	tree[i].lazy=0;          
	if(l==r){
		tree[i].min=be[l];
		tree[i].max=0;
		tree[i].sum=0;
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,i<<1);
	build(mid+1,r,i<<1|1);
	update(i);
} 
void pushlazy(int i) //lazy数组的操作 
{
	if(tree[i].lazy){ 
		tree[i<<1].lazy+=tree[i].lazy;
		tree[i<<1|1].lazy+=tree[i].lazy;
		tree[i<<1].max+=tree[i].lazy;
		tree[i<<1|1].max+=tree[i].lazy;
		tree[i].lazy=0;
	}
}
void add(int l,int r,int i)
{
	if(tree[i].l>=l && tree[i].r<=r){
		tree[i].max++; 		//当树的区间在所给区间的时候,a数组的元素+1,相当于tree[i].max++ 
		if(tree[i].max<tree[i].min){//当最大值小于最小值时,增加lazy,直接跳出 
			tree[i].lazy++;
			return;
		}
		else if(tree[i].l==tree[i].r && tree[i].max>=tree[i].min){
        //访问到根节点且当最大值大于等于最小值时,输出的sum++,并且使b数组+上原来的数 
			tree[i].sum++;
			tree[i].min+=be[tree[i].l];
			return;
		}
	}
	pushlazy(i); //使用lazy数,使其儿子节点更新 
	int mid=(tree[i].l+tree[i].r)>>1;
	if(l<=mid) add(l,r,i<<1);
	if(r>mid) add(l,r,i<<1|1);
	update(i);//更新爸爸节点 
}
int query(int l,int r,int i){
	if(l<=tree[i].l && r>=tree[i].r){ //如果在区间里面直接返回其值sum 
		return tree[i].sum;
	}
	pushlazy(i); //使用lazy数,使其儿子节点更新 
	int ans=0; //输出的答案 
	int mid=(tree[i].l+tree[i].r)>>1;
	if(l<=mid) ans+=query(l,r,i<<1);
	if(r>mid) ans+=query(l,r,i<<1|1);
	return ans;
}
int main()
{
	int n,m;
	while(scanf("%d %d",&n,&m)!=EOF){
		char str[66];
		for(int i=1;i<=n;i++)
		scanf("%d",&be[i]);
		build(1,n,1);
		int first,last;
		for(int i=1;i<=m;i++){
			scanf("%s %d %d",&str,&first,&last);
			if(str[0]=='a'){
				add(first,last,1);
			}
			else{
				int out=query(first,last,1);
				printf("%d\n",out);
			}
		}
	}
}
发布了13 篇原创文章 · 获赞 4 · 访问量 4202

猜你喜欢

转载自blog.csdn.net/yiyiLy/article/details/81216057