大连网络赛--Function--暴力||线段树

本文介绍了一种快速查询算法的优化方案,通过预处理数组找到每个位置的下一个小于等于当前值的位置,实现对区间函数F(l,r)的高效计算。提供了两种实现方式,一种是直接遍历查找,另一种是使用线段树进行优化,显著提高了查询效率。

Function

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


 

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

 

 

Source

2016 ACM/ICPC Asia Regional Dalian Online

 

 

Recommend

wange2014

求Al%....%AR。


预处理出每一个位置的X第一个小于等于X的位置。找到后退出。

查询时从区间i=l+1跳动到pos[i],然后要小于r即可。

#include <algorithm>    //STL通用算法
#include <bitset>     //STL位集容器
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>     //复数类
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>      //STL双端队列容器
#include <exception>    //异常处理类
#include <fstream>
#include <functional>   //STL定义运算函数(代替运算符)
#include <limits>
#include <list>      //STL线性列表容器
#include <map>       //STL 映射容器
#include <iomanip>
#include <ios>      //基本输入/输出支持
#include<iosfwd>     //输入/输出系统使用的前置声明
#include <iostream>
#include <istream>     //基本输入流
#include <ostream>     //基本输出流
#include <queue>      //STL队列容器
#include <set>       //STL 集合容器
#include <sstream>    //基于字符串的流
#include <stack>      //STL堆栈容器    
#include <stdexcept>    //标准异常类
#include <streambuf>   //底层输入/输出支持
#include <string>     //字符串类
#include <utility>     //STL通用模板类
#include <vector>     //STL动态数组容器
#include <cwchar>
#include <cwctype>
#define ll long long
using namespace std;
priority_queue<int,vector<int>,less<int> >q;
int dx[]= {-1,1,0,0,-1,-1,1,1};
int dy[]= {0,0,-1,1,-1,1,1,-1};
const int maxn = 100000+6;
const ll mod=10007;
int n,k,m;
int a[maxn];
int pos[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i=1; i<=n; i++)
        {
            int tmp=n+1;
            for(int j=i+1; j<=n; j++)
            {
                if(a[j]<=a[i])
                {
                    tmp=j;
                    break;
                }
            }
            pos[i]=tmp;
        }
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int l,r;
            scanf("%d %d",&l,&r);
            int ans=a[l];
            for(int i=l+1;i<=r;i=pos[i])
            {
                int v=a[i];
                ans%=v;
            }
            printf("%d\n",ans);
        }
    }
}

线段树做法:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int mxn=200010;
int n,a[mxn];
int mm[mxn],lc[mxn],rc[mxn],t;

int bu(int l,int r){
	int x=++t;
	if(l==r){
		mm[x]=a[l];
		return x;
	}
	int mi=(l+r)/2;
	lc[x]=bu(l,mi);
	rc[x]=bu(mi+1,r);
	mm[x]=min(mm[lc[x]],mm[rc[x]]);
	return x;
}
int ql,qr;
int que(int x,int l,int r,int v){
	if(mm[x]>v) return 0;
	if(l==r) return l;
	int mi=(l+r)/2,a;
	if(ql<=mi){
		a=que(lc[x],l,mi,v);
		if(a) return a;
	} 
	if(qr>mi) return que(rc[x],mi+1,r,v);
	return 0;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		t=0;
		bu(1,n);
		int m;
		scanf("%d",&m);
		while(m--){
			scanf("%d%d",&ql,&qr);
			int nw=a[ql];
			ql=ql+1;
			while(ql<=qr){
				int x=que(1,1,n,nw);
				if(!x) break;
				ql=x+1;
				nw%=a[x];
			}
			printf("%d\n",nw);
		}
	}
	return 0;
}













 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值