区间求最值 线段树

湖南师范大学 11460 区间求最值

区间求最值
 
Problem description
  给定一个长度为N 的数组,有q个询问,每个询问是求在数组的一段区间内那个元素的因子的个数最大,比如24的因子的个数就是8。 
Input
  首先是一个整数t,表示有t组测试数据,每组测试数据的第一行是一个整数N(1<=N<=10^6),第二行有N个整数ai(1<=ai<=10^6,i=1,2,.....N)表示数组的元素。第三行有一个整数q(1<=q<=10^5),代表有q个询问,接下来每一行有两个整数,li,ri(li<=ri,li>=1,ri<=N).代表数组的一段区间,并且li+1>=li,ri+1>=ri
Output
  对于每组数据的每个询问都输出一个整数表示在这段区间里面元素因子个数的最大值。
Sample Input
1
10
2 3 5 6 9 11 12 36 39 44
3
2 6
3 8
3 9
Sample Output
4
9
9
Problem Source

用朴素线段树和st算法都超内存

zkw线段树:

参考:http://www.cnblogs.com/markliu/archive/2012/05/30/2527020.html

//20716KB	781ms
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define N 1000010
int T[N*4],M;
int yin[N];
void inti()
{
    int i,j;
    yin[1]=0;
    for(i=1;i<N;i++)
    {
        for(j=i;j<N;j+=i)yin[j]++;
    }
 //  for(i=0;i<100;i++)printf("%d %d\n",i,yin[i]);
}
void seg_build(int n){
    int i,x;
    for(M=1;M<=n+1;M*=2);
    for(i=1+M;i<=n+M;i++){
        scanf("%d",&x);
        T[i]=yin[x];
    }
    for(i=M-1;i;i--) T[i]=max(T[i*2],T[i*2+1]);
}

int seg_query(int s,int t){
    int maxc=-1;
    for(s=s+M-1,t=t+M+1;s^t^1;s/=2,t/=2){
        if(s%2==0) maxc=max(maxc,T[s^1]);
        if(t%2==1) maxc=max(maxc,T[t^1]);
    }
    return maxc;
}

int main()
{
    inti();
    int n,m,a,b;
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        memset(T,0,sizeof(T));
        seg_build(n);
        scanf("%d",&m);
        while(m--){
            scanf("%d%d",&a,&b);
            printf("%d\n",seg_query(a,b));
        }
    }
    return 0;
}

网上题解,想不通为什么这个能过,还比我的省时间

参考:http://blog.csdn.net/u012964281/article/details/29578869

//8864KB	765ms
#include <cstdio>
#include <cstring>
#define maxn 1000005
int find[maxn];
int num[maxn];
int main()
{
	memset(find, 0, sizeof(find));
	for (int i = 1; i < maxn; i++){
		for (int j = i; j < maxn; j += i)
			find[j]++;
	}
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n, q;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
			scanf("%d", &num[i]);
		scanf("%d", &q);
		int a, b, ans = -1;
		int aa, bb, sign;
		scanf("%d%d", &a, &b);
		aa = a, bb = b;
		for (int i = a; i <= b; i++)
			if (ans < find[num[i]]){
				ans = find[num[i]];
				sign = i;
			}

		printf("%d\n", ans);
		--q;
		while (q--)
		{
			scanf("%d%d", &a, &b);
			if (sign >= aa&&sign <= a){
				ans = -1;
				for (int i = a; i <= b; i++)
				if (ans < find[num[i]]){
					ans = find[num[i]];
					sign = i;
				}
			}
			else
			{
				for (int i = bb; i <= b; i++)
				if (ans < find[num[i]]){
					ans = find[num[i]];
					sign = i;
				}
			}
			aa = a, bb = b;
			printf("%d\n", ans);
		}
	}
	return 0;
}

区间求最值 线段树,布布扣,bubuko.com

时间: 2024-10-10 04:37:01

区间求最值 线段树的相关文章

hdu4521-小明系列问题——小明序列(线段树区间求最值)

题意:求最长上升序列的长度(LIS),但是要求相邻的两个数距离至少为d,数据范围较大,普通dp肯定TLE.线段树搞之就可以了,或者优化后的nlogn的dp. 代码为  线段树解法. 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <stack> 7 #include <cct

poj3264(线段树区间求最值)

题目连接:http://poj.org/problem?id=3264 题意:给定Q(1<=Q<=200000)个数A1,A2,```,AQ,多次求任一区间Ai-Aj中最大数和最小数的差. 线段树功能:区间求最值,O(logN)复杂度查询 #pragma comment(linker,"/STACK:102400000,102400000") #include <cstdio> #include <cstring> #include <stri

HDU - 1754 I Hate It (线段树区间求最值)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754 题意:线段树的单点更新和区间求最值 模板题,,,???,, 1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 5 typedef long long LL; 6 const int N=200010; 7 8 LL ans; 9 LL max(LL a,LL b){ 10 if(a>b) r

动态求区间K大值(权值线段树)

我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和前一颗树没有关系,so,并不需要可持久化,一个朴素的权值线段树就可以啦. 我们知道普通的线段树是刚开始就把所有的节点都开了,但我们发现并不需要,因为每个点里的操作并不是很多,很大一部分的节点是用不到的,那么我们就可以不开.用Ls 和 Rs 来记左右儿子的地址,随用随开即可. #include<bit

权值线段树求逆序对问题

我们都知道,求逆序对数量可以用归并排序解决.但是用归并排序只能解决静态的序列问题,没有扩展的区间.因此就有了用权值线段树求逆序对的方法. 1 #include<iostream> 2 #include<iomanip> 3 #include<ctime> 4 #include<climits> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #inc

BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

题目大意:有一些位置,这些位置上可以放若干个数字.现在有两种操作. 1.在区间l到r上添加一个数字x 2.求出l到r上的第k大的数字是什么 思路:这种题一看就是树套树,关键是怎么套,怎么写.(话说我也不会来着..)最容易想到的方法就是区间线段树套一个权值线段树,但是区间线段树上的标记就会变得异常复杂.所以我们就反过来套,用权值线段树套区间线段树.这样修改操作在外线段树上就变成了单点修改,外线段树就不用维护标记了.在里面的区间线段树上维护标记就容易多了.具体实现见代码. CODE: #includ

【BZOJ2653】middle,主席树(非权值线段树)维护区间01信息+二分答案

传送门 写在前面:虽然这是一道我再也不想写的题目,但很好很有价值 思路: cxlove大神: 要求中位数最大,首先二分中位数,然后判断可行不可行. 判断X可行不可行,对于区间内的数,凡是>=X的标为1,否则为-1.这样的话,求一次最大区间和 如果大于等于0,则说明可行. 这要求我们不能像之前那样建立权值线段树的主席树(区间即为权值)了,而是以权值为下标,维护区间[1,n]的信息,可能有点拗口,这里就理解是我们平常写的普通线段树好了,只是这里是n棵由于根的不同而信息不同的线段树 具体实现 对于题目

hdu 1754 I Hate It(树状数组区间求最值)2007省赛集训队练习赛(6)_linle专场

题意: 输入一行数字,查询第i个数到第j个数之间的最大值.可以修改其中的某个数的值. 输入: 包含多组输入数据. 每组输入首行两个整数n,m.表示共有n个数,m次操作. 接下来一行包含n个整数. 接下来m行,每行包含一个字母s,两个整数a,b. 当s为’Q’,表示查询第a个数到第b个数之间的最大值. 当s为’U’,表示将第a个数更改为b. 输出: 每次查询输出一个结果,每次输出占一行. 题解: 点修改区间求最值,可以用树状数组模板. 具体见代码—— 1 #include <cstdio> 2

【bzoj3065】带插入区间K小值 替罪羊树套权值线段树

题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少.这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问.这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少.这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问.(orz 主席