zoukankan      html  css  js  c++  java
  • 【bzoj4491】我也不知道题目名字是什么 离线扫描线+线段树

    题目描述

    给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串

    输入

    第一行n,表示A数组有多少元素
    接下来一行为n个整数A[i]
    接下来一个整数Q,表示询问数量
    接下来Q行,每行2个整数l,r

    输出

    对于每个询问,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串

    样例输入

    9
    1 2 3 4 5 6 5 4 3
    5
    1 6
    1 7
    2 7
    1 9
    5 9

    样例输出

    6
    6
    5
    6
    4


    题解

    离线扫描线+线段树

    考虑询问 $[l,r]$ ,对于选出子串的左端点i,右端点一定是 $min(pos[i],r)$ ,其中 $pos[i]$ 表示从 $i$ 开始的最长不上升子串的最终位置。

    那么我们先扫一遍整个序列,求出从每个位置开始的最长不上升子串的最终位置。

    然后把 $min(pos[i],r)$ 分为两种情况,即求满足 $pos[i]le r$ 的所有i中最大的 $pos[i]-i$ ,和满足 $pos[i]>r$ 的所有 $i$ 中最大的 $r-i$(即最大的 $-i$ )

    把序列位置看作 $(i,pos[i])$,询问看作 $(l,r)$ ,相当于二维平面上的点,显然这个问题可以用离线扫描线+线段树的方法来解决。

    把序列位置按照 $pos[i]$ 从小到大排序,把询问按照 $r$ 从小到大排序。对于 $pos[i]le r$ 的情况,从前往后扫描询问,把所有 $pos[i]le r$ 的 $i$ 在线段树的 $i$ 的位置加入 $pos[i]-i$ ,询问直接在线段树求 $[l,r]$ 的最大值。 $pos[i]>r$的情况同理。

    时间复杂度 $O(nlog n)$

    #include <cstdio>
    #include <algorithm>
    #define N 50010
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    using namespace std;
    struct data
    {
    	int l , r , id;
    	bool operator<(const data &a)const {return r < a.r;}
    }v[N << 1] , q[N];
    int a[N] , tot , mx[N << 2] , ans[N];
    void build(int l , int r , int x)
    {
    	mx[x] = -1 << 30;
    	if(l == r) return;
    	int mid = (l + r) >> 1;
    	build(lson) , build(rson);
    }
    void update(int p , int v , int l , int r , int x)
    {
    	mx[x] = max(mx[x] , v);
    	if(l == r) return;
    	int mid = (l + r) >> 1;
    	if(p <= mid) update(p , v , lson);
    	else update(p , v , rson);
    }
    int query(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e) return mx[x];
    	int mid = (l + r) >> 1 , ans = -1 << 30;
    	if(b <= mid) ans = max(ans , query(b , e , lson));
    	if(e > mid) ans = max(ans , query(b , e , rson));
    	return ans;
    }
    int main()
    {
    	int n , m , i , p;
    	scanf("%d" , &n);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
    	for(p = i = 1 ; i <= n ; i ++ )
    		if(a[i] < a[i - 1])
    			while(p < i)
    				v[++tot].l = p ++  , v[tot].r = i - 1;
    	while(p <= n) v[++tot].l = p ++  , v[tot].r = n;
    	for(p = i = 1 ; i <= n ; i ++ )
    		if(a[i] > a[i - 1])
    			while(p < i)
    				v[++tot].l = p ++  , v[tot].r = i - 1;
    	while(p <= n) v[++tot].l = p ++  , v[tot].r = n;
    	scanf("%d" , &m);
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &q[i].l , &q[i].r) , q[i].id = i;
    	sort(v + 1 , v + tot + 1) , sort(q + 1 , q + m + 1);
    	build(1 , n , 1);
    	for(p = i = 1 ; i <= m ; i ++ )
    	{
    		while(p <= tot && v[p].r <= q[i].r) update(v[p].l , v[p].r - v[p].l + 1 , 1 , n , 1) , p ++ ;
    		ans[q[i].id] = max(ans[q[i].id] , query(q[i].l , q[i].r , 1 , n , 1));
    	}
    	build(1 , n , 1);
    	for(p = tot , i = m ; i ; i -- )
    	{
    		while(p && v[p].r > q[i].r) update(v[p].l , -v[p].l , 1 , n , 1) , p -- ;
    		ans[q[i].id] = max(ans[q[i].id] , query(q[i].l , q[i].r , 1 , n , 1) + q[i].r + 1);
    	}
    	for(i = 1 ; i <= m ; i ++ ) printf("%d
    " , ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    时间使用
    关于Dubbo说明及备注
    jQuery 的function简单备注
    Eclipse插件
    存储过程和视图的区别
    easyUi jqgrid search
    Python3内置函数——reversed() = 翻转我的世界
    你追求的目标正确吗
    Python3正则表示式(3)
    英语口语学习笔记(13)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7991727.html
Copyright © 2011-2022 走看看