zoukankan      html  css  js  c++  java
  • 序列 [树状数组+离散化]

    序列

    题目描述

    给定两个长度为n的序列 (a, b) 。你需要选择一个区间([l,r]),使得 (a_l+…+a_rgeqslant 0)(b_l+…+b_rgeqslant 0)。最大化你选择的区间长度。

    输入格式

    第一行一个整数 (n),第二行 (n) 个整数 (a_1 o a_n),第三行 (n) 个整数 (b_1 o b_n)

    输出格式

    一行一个整数表示(max(r-l+1))。保证至少有一个区间满足条件。

    样例

    样例输入

    5
    2 -4 1 2 -2
    -2 3 1 -3 1
    

    样例输出

    1
    

    数据范围与提示

    对于 (20\%) 的数据,(nleqslant 5000)

    对于 (60\%) 的数据,(nleqslant 10^5)

    对于 (100\%) 的数据,(1leqslant nleqslant 10^6,|a_i|, |b_i|leqslant 10^9)。 数据有一定梯度。

    分析

    看到题目就能得到三个柿子,也就是个三维偏序:

    [suma_r-suma_lgeqslant 0\ sumb_r-sumb_lgeqslant 0\ r-lgeqslant 0]

    但是三个不等式是非常难以维护的,所以我们考虑简化一下这三个式子。

    我们可以首先让一个条件满足,我们先按 (suma) 的大小升序排序,这样第一个式子就绝对满足了,我们只需要考虑剩下的二维偏序问题。

    因为 (sumb) 的范围肯定要比 (long long) 还大,所以我们需要离散化来进行存储。因为我们需要满足在 (sumb) 的条件满足的情况下,找到当前这个位置向左拓展的最小的左边界,这个区间的长度就是答案。

    根据上边所说的,我们就可以使用树状数组来维护每个 (sumb) 的最小左端点,用 (sumb) 当作下标(离散化之后的),用当前这个值的位置来更新值,在查询的时候查询这个位置即可,答案就是当前值的位置减去查询到的左端点,取 (max) 即可。

    代码

    
    
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6+10;
    ll suma[maxn],sumb[maxn];
    struct Node{
    	ll a,b,id;
    }jl[maxn];
    ll n;
    inline ll read(){
    	ll s = 0,f = 1;
    	char ch = getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch))s=s*10+ch-'0',ch=getchar();
    	return s*f;
    }
    int t[maxn];
    int lowbit(int x){
    	return x & -x;
    }
    void modify(int x,int val){//修改最小值
    	while(x <= n){
    		t[x] = min(t[x],val);
    		x += lowbit(x);
    	}
    }
    int query(int x){//查询最小左端点
    	int res = 0x3f3f3f3f;
    	while(x){
    		res = min(res,t[x]);
    		x -= lowbit(x);
    	}
    	return res;
    }
    bool cmp(Node x,Node y){//按suma排序
    	return x.a < y.a;
    }
    int main(){
    	freopen("B.in","r",stdin);
    	freopen("B.out","w",stdout);
    	memset(t,0x3f,sizeof(t));//因为要维护最小的左端点,所以初始化极大值
    	n = read();
    	for(register int i = 1;i <= n;++i){
    		ll x = read();
    		jl[i].id = i;
    		suma[i] = suma[i-1] + x;
    		jl[i].a = suma[i];
    	}
    	for(register int i = 1;i <= n;++i){
    		ll x = read();
    		sumb[i] = sumb[i-1] + x;
    		jl[i].b = sumb[i];
    	}
    	int ans = 1;
    	for(register int i = 1;i <= n;++i){
    		if(sumb[i] >= 0 && suma[i] >= 0){//先提前处理一下,不然会挂
    			ans = max(ans,i);
    		}
    	}
    	sort(jl+1,jl+n+1,cmp);//按suma排序,去掉一个限制条件
    	//以下两行离散化
    	sort(sumb+1,sumb+n+1);
    	int q = unique(sumb+1,sumb+n+1)-sumb-1;
    	for(int i=1;i<=n;++i){
    		int pos = lower_bound(sumb+1,sumb+q+1,jl[i].b) - sumb;//找到这个sumb的位置(也就是离散化后的值)
    		modify(pos,jl[i].id);//修改
    		ans = max((ll)ans,jl[i].id - query(pos));//查询并更新答案
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    部署 AppGlobalResources 到 SharePoint 2010
    还原一个已删除的网站集
    使用仪表板设计器配置级联筛选器 (SharePoint Server 2010 SP1)
    File or arguments not valid for site template
    Pex and Moles Documentation
    Content Query Webpart匿名访问
    Running Moles using NUnit Console from Visual Studio
    Calling a WCF Service using jQuery in SharePoint the correct way
    Updating Content Types and Site Columns That Were Deployed as a Feature
    asp.net中判断传过来的字符串不为空的代码
  • 原文地址:https://www.cnblogs.com/Vocanda/p/13504378.html
Copyright © 2011-2022 走看看