HDU 6315 Naive Operations(线段树)

Naive Operations

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

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

 

题意:

很简单,让你完成两个操作,更新a[l..r]+1,查询Σ(i∈[l,r]) [ai/bi]

a一开始都为0,b是数1-n的一个任意排列

解析:

这道题关键一点就是它答案更新的时间复杂度。

因为查询最多只有n个,假如他全是查询的话,那么答案最大就是Σ[n/i]  (i∈[l,r])

这个其实就是一个1/1+1/2+1/3+...1/n的调和级数,大佬说这个是O(nlogn)的复杂度。

意思就是说让[ai/bi]这个答案+1的操作最多只会进行nlogn次。

那么对于某一次更新可以让[ai/bi]+1的话,我们只要更新到这个叶子结点就可以了

这个复杂度最多是O(nlogn*logn)依然可以接受

那么就下来我们应该做的就是怎么让那些不会使答案+1的更新可以完成正确的操作。

这些"无用"的更新肯定不能继续更新到点了,因为这样复杂度有重回O(n*n)了。

那么对于每一个节点我们都给他们赋值对应的bi,这样我们就只需要将ai对应的节点-1,

当ai对应节点=0时,就说明这个节点已经被加了bi次,那么对应的答案[ai/bi]就可以+1

这时我们就可以维护区间的最小值以及最小值是来自于左子树还是右子树。

对于无用更新我们只需要更新最小值就可以了。每一次无用更新我们都让对应区间的最小值-1,

然后对整棵树进行更新,如果一个区间的最小值为0,那么我们就对应最小值的方向往下搜,

直到搜到最小值为0的叶子结点为止,然后更新叶子的状态,答案+1。

所以每一次更新,我们都首先更新区间最小值,然后更新整棵树内最小值为0的叶子节点。

之后查询就不同的线段树查询就可以了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN = 1e5+100;
int b[MAXN];
char str[10];
#define lch root<<1
#define rch (root<<1)|1
typedef long long ll;

typedef struct node
{
	//int y;
	ll ans;
	int minn;
	int pos;
}node;

node Btree[MAXN*5];
int mark[MAXN*4];


inline void push_up(int root)
{
	Btree[root].ans=Btree[root<<1].ans+Btree[(root<<1)|1].ans;
	if(Btree[lch].minn>Btree[rch].minn)
	{
		Btree[root].minn=Btree[rch].minn;
		Btree[root].pos=1;
	}
	else if(Btree[lch].minn<Btree[rch].minn)
	{
		Btree[root].minn=Btree[lch].minn;
		Btree[root].pos=2;
	}
	else
	{
		Btree[root].minn=Btree[lch].minn;
		Btree[root].pos=3;
	}

}

void build(int l,int r,int root)  //l,r表示他们在stu中的下标,root表示他们在线段树中的坐标
{
	if(l>r)return;
	if(l==r)
	{
		//Btree[root].y=b[l];
		Btree[root].ans=0;
		mark[root]=0;
		Btree[root].pos=0;
		Btree[root].minn=b[l];
		return ;
	}

	int mid=(l+r)>>1;
	mark[root]=0;
	build(l,mid,root<<1);
	build(mid+1,r,(root<<1)|1);

	
	push_up(root); 
}

inline void pushDown(int root)
{
	if(mark[root]!=0)
	{
		mark[lch]+=mark[root];
		mark[rch]+=mark[root];

		Btree[lch].minn-=mark[root];
		Btree[rch].minn-=mark[root];

		mark[root]=0;
	}
}

void update(int root,int s1,int e1,int s2,int e2)   //s1,e1表示当前区间,s2,e2表示目标区间
{
	if(e1<s2||s1>e2)
		return;
	if(s1>e1)return;
	if(s2<=s1&&e1<=e2)
	{

		Btree[root].minn-=1;
		mark[root]+=1;
		if(s1==e1)
		{
			mark[root]=0;
			Btree[root].ans+=Btree[root].minn==0?1:0;
			Btree[root].minn=Btree[root].minn==0?b[s1]:(Btree[root].minn);
		}
		return;
	}
	pushDown(root);
	int mid=(s1+e1)>>1;
	if(s2<=mid)
		update(root<<1,s1,mid,s2,e2);
	if(mid+1<=e2)
		update((root<<1)|1,mid+1,e1,s2,e2);
	push_up(root);
}

void updateone(int root,int s1,int e1)  
{
	if(s1>e1)return;
	if(s1==e1)
	{
		Btree[root].ans+=Btree[root].minn==0?1:0;
		Btree[root].minn=Btree[root].minn==0?b[s1]:(Btree[root].minn);
		return;
	}
	pushDown(root);
	int mid=(s1+e1)>>1;
	if(Btree[root].minn==0&&Btree[root].pos>1)
		updateone(root<<1,s1,mid);
	if(Btree[root].minn==0&&Btree[root].pos%2)
		updateone((root<<1)|1,mid+1,e1);
	push_up(root);
}

ll query(int root,int s1,int e1,int s2,int e2)
{
	if(e1<s2||s1>e2)
		return 0;
	if(s1>e1)return 0;
	if(s1>=s2&&e1<=e2)
	{
		return Btree[root].ans;
	}

	//pushDown(root);
	int mid=(s1+e1)>>1;
	int ans=0;
	if(s2<=mid)ans+=query(root<<1,s1,mid,s2,e2);
	if(mid+1<=e2) ans+=query((root<<1)|1,mid+1,e1,s2,e2);
	return ans;
}




int main()
{
	int n,q;
	while (scanf("%d%d",&n,&q)!=EOF)
	{
		for(int i=1;i<=n;i++) scanf("%d",&b[i]);
		build(1,n,1);
		for(int i=0;i<q;i++)
		{
			int l,r;
			scanf("%s%d%d",str,&l,&r);
			if(strcmp("add",str)==0)
			{
				update(1,1,n,l,r);
				updateone(1,1,n);
			}
			else
			{
				ll ans=query(1,1,n,l,r);
				printf("%lld\n",ans);
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37025443/article/details/81216743