Hdu-5875 Function(树上倍增st算法)

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) (1lrN) is defined as:
F(l,r)={AlF(l,r1) 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(1N100000) .
  The second line contains N space-separated positive integers: A1,,AN (0Ai109) .
  The third line contains an integer M denoting the number of queries.
  The following M lines each contain two integers l,r (1lrN) , 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
 

题意:给n个数字的数列,m个询问,问F[l,r]是多少,F[l,r] = F[l,r-1] % a[r],当l = r时F[l,r] = a[l].


分析: 注意每个数最多取有效模log(a[i])次就会变成0,所以我们可以把数列中每个元素向它右边第一个小于等于它的元素连边,最后会形成一个森林,每次询问在线在森林上倍增。n*log(n)*log(a[i]).


#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
#define N 100005
using namespace std; 
typedef long long ll;
int T,n,m,fa[N][35],a[N];
int Find_pos(int u,int val)
{
	int now = log2(n-u+1) + 1;
	while(now >= 0)
	{
		if(a[fa[u][now]] > val && a[fa[u][now+1]] <= val) u = fa[u][now];
		now--;
	}
	if(a[u] > val) u = fa[u][0];
	return u;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		memset(fa,0,sizeof(fa));
		a[0] = -1;
		scanf("%d",&n);
		for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
		for(int i = n-1;i;i--)
		{
			fa[i][0] = Find_pos(i+1,a[i]);
			for(int j = 1;(1<<j) <= n;j++)
			 fa[i][j] = fa[fa[i][j-1]][j-1];
		}
		scanf("%d",&m);
		for(int i = 1;i <= m;i++)
		{
			int l,r,ans;
			scanf("%d%d",&l,&r);
			int now = l+1;
			ans = a[l];
			while(now && now <= r && ans)
			{
				ans %= a[now];
				now = Find_pos(now,ans);
			}
			printf("%d\n",ans);
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值