NKOI 2753 区间连续值

区间连续值

Time Limit:10000MS  Memory Limit:65536K

Total Submit:58 Accepted:49

Case Time Limit:1000MS

Description

有一数列只有0和1构成,数列中数字个数为为n。

现在有m个形式为x y的提问,询问区间[x,y]中,最多有多少个连续的1。

对于每个询问,请你快速做出回答

Input

第一行,两个整数n和m

第二行,n个空格间隔的数字,表示数列

接下来m行,每行两个空格间隔的整数x和y,表示一个询问(x<=y)

Output

m行,每行一个整数,对应询问的答案

Sample Input

9 3
1 0 0 0 1 1 1 0 1
1 9
3 6
2 4

Sample Output

3
2
0

Hint

1<=n,m<=100000

首先我们在结构体中用l1表示从左开始最多的连续1,r1表示从右开始最多的连续1,mid1表示中间最多的连续1,max1表示这一段中最多的连续1

当一个区间取到最大连续1时,这个最长的“1”段要么包含左端点,要么包含右端点,要么两个都不包含,我们可以看成这个"1"段位于左端,右端和中间

#include<cstdio>
using namespace std;
const int maxn=100005;
inline void _read(int &x){
	char t=getchar();bool sign=true;
	while(t<'0'||t>'9')
	{if(t=='-')sign=false;t=getchar();}
	for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
	if(!sign)x=-x;
}
int n,m,tot,a,b,s[maxn];
struct wk{int a,b,left,right,l1,r1,mid1,max1;}tree[2*maxn];
void update(int r){
	int ls=tree[r].left,rs=tree[r].right;
	if(tree[ls].l1==tree[ls].b-tree[ls].a+1)
	    tree[r].l1=tree[ls].max1+tree[rs].l1;
	else tree[r].l1=tree[ls].l1;//讨论Tree[p].L1
	if(tree[rs].r1==tree[rs].b-tree[rs].a+1)
	    tree[r].r1=tree[rs].max1+tree[ls].r1;
	else tree[r].r1=tree[rs].r1;//讨论Tree[p].R1
	tree[r].max1=max(tree[ls].max1,max(tree[rs].max1,tree[ls].r1+tree[rs].l1));//Tree[Ls].R1+Tree[Rs].L1就是前面所述的Tree[p].Mid1
}
void buildtree(int x,int y){
	int r=++tot;
	tree[r].a=x;tree[r].b=y;
	if(x<y){
		int mid=(x+y)>>1;
		tree[r].left=tot+1;
		buildtree(x,mid);
		tree[r].right=tot+1;
		buildtree(mid+1,y);
		update(r);
	}
	else {
		tree[r].l1=tree[r].r1=tree[r].max1=s[x];
		return;
	}
}
int getans(int r){
	if(tree[r].a>=a&&tree[r].b<=b)return tree[r].max1;
	if(tree[r].a>b||tree[r].b<a)return 0;
	int temp=0,lenl=0,lenr=0,lenm=0,ls=tree[r].left,rs=tree[r].right;
	if(a<=tree[ls].b)lenl=getans(ls);//左儿子相交区域的最大连续1
	if(b>=tree[rs].a)lenr=getans(rs);//右儿子相交区域的最大连续1
	if(a<=tree[ls].b&&b>=tree[rs].a){
		temp=tree[ls].b-a+1;//右侧长度
		lenm+=min(temp,tree[ls].r1);
		temp=b-tree[rs].a+1;//左侧长度
		lenm+=min(temp,tree[rs].l1);
	}
	return max(lenl,max(lenr,lenm));
}
int main(){
	_read(n);_read(m);
	for(int i=1;i<=n;i++)
	    _read(s[i]);
	buildtree(1,n);
	while(m--){
		_read(a);_read(b);
		printf("%d\n",getans(1));
	}
}
时间: 2024-10-16 12:38:40

NKOI 2753 区间连续值的相关文章

POJ - 3264 Balanced Lineup (RMQ问题求区间最值)

RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题. Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description For the daily

RAM区间最值

RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题. 简介 主要方法及复杂度如下: 1.朴素(即搜索),O(n)-O(qn) online. 2.线段树,O(n)-O(qlogn) online. 3.ST(实质是动态规划),O(nlogn)-O(1) online. ST算法(Sparse Table),以求最大值为

【RMQ】 区间最值查询详解

1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值.这两个问题是在实际应用中经常遇到的问题,下面介绍一下解决这两种问题的比较高效的算法.当然,该问题也可以用线段树(也叫区间树)解决,算法复杂度为:O(N)~O(logN),这里我们暂不介绍. 2.RMQ算法 对于该问题,最容易想到的解决方案是遍历,复杂度是O(n).但当数据量

线段树 --- (单点更新、求区间最值、模板题)

A - 敌兵布阵 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营 地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工 兵营地的人数都有可能发生

ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和

题意:给你n个球排成一行,初始都为黑色,现在给一些操作(L,R,color),给[L,R]区间内的求染上颜色color,'w'为白,'b'为黑.问最后最长的白色区间的起点和终点的位置. 解法:先离散化,为了防止离散后错误,不仅将L,R离散,还要加入L+1,L-1,R+1,R-1一起离散,这样就绝不会有问题了.然后建线段树,线段树维护四个值: 1.col  区间颜色  0 表示黑  1 表示白  -1表示无标记 2.maxi 区间内最大白区间的长度,由于白色用1表示,所以最大白区间的长度即为区间最

RMQ(求区间最值问题)

学习博客:https://blog.csdn.net/qq_31759205/article/details/75008659 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干次询问RMQ(i,j),返回数列A中下标在区间[i,j]中的最小/大值. 本文介绍一种比较高效的ST算法解决这个问题.ST(Sparse Table)算法可以在O(nlogn)时间内进行预处理,然后在O(1)时间内回答每个查询. 第一步:预处

树状数组维护区间最值

在区间求和时,我们只需求出 [1, r],[1,l?1],利用前缀和的可减性,得到区间 [l,r] 的和. 但区间最值不满足这个性质. 我们可以把区间 [l,r] 拆分成若干个子区间,再合并得到答案. 画图可知,max_i需要的 max 只有 max_{i-2^0}, max_{i-2^1}, max_{i-2^2} ... max_{i-lowbit(i)+1}. 修改 void change(int r) { c[r] = a[r]; for(int i = 1; i < lowbit(r)

树状数组求区间最值

树状数组求区间最值 树状数组(Binary Index Tree)利用二进制的一些性质巧妙的划分区间,是一种编程,时间和空间上都十分理想的求区间和的算法,同样我们可以利用树状数组优美的区间划分方法来求一个序列的最值 约定以 num[]  表示原数组, 以 idx[] 表示索引数组, Lowbit(x)=x&(-x) 树状数组求和时通过构造数组 idx[] 使 idx[k]=sum(num[tk]), tk [k-Lowbit(k)+1,k], 使用同样的方法构造最值索引数组: 以最大值为例, 先

算法模板——线段树3(区间覆盖值+区间求和)

实现功能——1:区间覆盖值:2:区间求和 相比直接的区间加,这个要注重顺序,因为操作有顺序之分.所以这里面的tag应该有个pushup操作(本程序中的ext) 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b,d:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end;