HDU - 5875 Function —— 预处理?线段树

41 篇文章 1 订阅

Function

Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3915    Accepted Submission(s): 1250


 

Problem Description

The shorter, the simpler. With this problem, you should be convinced of this truth.
  
  You are given an array A of N postive integers, and M queries in the form (l,r). A function F(l,r) (1≤l≤r≤N) is defined as:
F(l,r)={AlF(l,r−1) modArl=r;l<r.
You job is to calculate F(l,r), for each query (l,r).

 

 

Input

There are multiple test cases.
  
  The first line of input contains a integer T, indicating number of test cases, and T test cases follow. 
  
  For each test case, the first line contains an integer N(1≤N≤100000).
  The second line contains N space-separated positive integers: A1,…,AN (0≤Ai≤109).
  The third line contains an integer M denoting the number of queries. 
  The following M lines each contain two integers l,r (1≤l≤r≤N), representing a query.

 

 

Output

For each query(l,r), output F(l,r) on one line.

 

 

Sample Input

1 3 2 3 3 1 1 3

 

 

Sample Output

2

题意:

问L位置的数模L+1,L+2....R的结果是多少

思路:

数模比它大的数是没有意义的,所以只要每次找它后面到R的区间比它小的数,取模后再找比结果更小的数

可以用线段树来查找,预处理的算法最坏情况下是N^2应该是过不了,说明数据比较水 -。-

更正:想错了,不是n^2的复杂度,取模之后数会减小一半,所以最多是log1e9

线段树:

#include <bits/stdc++.h>
using namespace std;
struct node
{
	int l,r;
	int id;
	int w;
};
struct node tree[400100];
int n,cnt,m;
int num[100100];
void built(int i,int l,int r)
{
	tree[i].l=l;
	tree[i].r=r;
	if(l==r)
	{
		tree[i].w=num[++cnt];
		tree[i].id=cnt;
		return;
	}
	int mid=(l+r)>>1;
	built(i<<1,l,mid);
	built(i<<1|1,mid+1,r);
	tree[i].w=min(tree[i<<1].w,tree[i<<1|1].w);
}
void query(int i,int l,int r,int v,int &pos)
{
	if(tree[i].w>v)
	return;
	if(tree[i].l>r||tree[i].r<l)
	return;
	int mid=(tree[i].l+tree[i].r)>>1;
	if(tree[i].l==tree[i].r)
	{
		pos=tree[i].id;
		return;
	}
	int tmp=pos;
	query(i<<1,l,r,v,pos);
	if(pos!=tmp)
	return;
	query(i<<1|1,l,r,v,pos);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		scanf("%d",&num[i]);
		cnt=0;
		built(1,1,n);
		scanf("%d",&m);
		int x,y;
		while(m--)
		{
			scanf("%d%d",&x,&y);
			int ans=num[x];
			int pos=x;
			while(pos+1<=y)
			{
				int tmp=pos;
				query(1,pos+1,y,ans,pos);
				if(tmp==pos)
				break;
				ans%=num[pos];
			}
			printf("%d\n",ans);
		}
	}
}

预处理:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
int n,m;
int num[100010];
int to[100010];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(to,-1,sizeof to);
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		scanf("%d",&num[i]);
		for(int i=1;i<=n;i++)
		{
			for(int j=i+1;j<=n;j++)
			{
				if(num[j]<=num[i])
				{
					to[i]=j;
					break;
				}
			}
			if(to[i]==-1)
			to[i]=n;
		}
		to[n]=n+1;
		scanf("%d",&m);
		while(m--)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			int ans=num[x];
			x=to[x];
			while(x<=y)
			{
				ans%=num[x];
				x=to[x];
			}
			printf("%d\n",ans);
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值