• 序列「树状数组维护偏序」


    序列「树状数组维护偏序」

    题目描述

    给定两个长度为 (n) 的序列 (a, b)

    你需要选择一个区间 ([l, r]),使得 (a_l+…+a_r>=0)(b_l+…+b_r>=0)。最大化你选择的区间长度。

    输入格式

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

    输出格式

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

    样例

    样例输入

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

    样例输出

    1
    

    数据范围与提示

    对于(20\%) 的数据,(n<=5000)

    对于(60\%) 的数据,(n<=10^5)

    对于(100\%) 的数据,(1<=n<=10^6)(|ai|, |bi|<=10^9)。 数据有一定梯度。

    思路分析

    • 又是一个求和区间有关的题,二话不说先上前缀和,那么就可以立刻得出一个结论,即 (suma[r]-suma[l-1]>=0)(sumb[r]-sumb[l-1]>=0)
    • 将上面的柿子稍微运用小学知识处理一下就是 (suma[r]>=sum[l-1])(sumb[r]>=sum[l-1]) ,满足这样条件的序列,我们称之为偏序,再加上 (r>=l) ,就成了一个维护三维偏序的题
      • 对于 (r>=l) 这一维,由于实际上并不会对答案产生什么实际影响,所以完全可以忽略掉。
      • 所以接下来要做的就是在保证另两维其中一个是偏序的情况下,(直接排序即可),再去维护另一维
      • 那么另一维怎么维护呢,因为我们还要保证答案最优,所以要让值小的越靠前越好,且由于会对后面的区间均产生影响,所以我们使用树状数组,因为数据太大线段树会炸
      • 还有一个细节就是,因为我们所需要的是相对位置,所以如果根据原有值建立树状数组,那树状数组也会吃不消,这时完全可以离散化处理,这样可以保证相对位置不会变

    Code

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define N 1000010
    #define int long long
    using namespace std;
    inline int read(){
    	int x=0,f=1;
    	char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    const int inf = 0x3f3f3f3f;
    int n,size,tr[N],ans=1,a[N],b[N],c[N]; //c用来处理离散化后的sumb
    struct node{int a,b,id;}s[N]; //a为suma,b为sumb
    inline bool cmp(node x,node y){
    	return x.a<y.a;
    }
    inline int lowbit(int x){
    	return x&(-x);
    }
    void modify(int x,int v){
    	while(x<=size){
    		tr[x] = min(tr[x],v);
    		x+=lowbit(x);
    	}
    }
    int query(int x){
    	int res = inf;
    	while(x){
    		res = min(res,tr[x]);
    		x-=lowbit(x);
    	}
    	return res;
    }
    signed main(){
    	n = read();
    	c[++size] = 0;
    	for(int i = 1; i <= n; i++) s[i].a = s[i-1].a + read();
    	for(int i = 1; i <= n; i++) s[i].b = s[i-1].b + read(),s[i].id = i,c[++size] = s[i].b;
    	for(int i = 1;i <= n;i++){
    		if(s[i].a>=0&&s[i].b>=0)ans = max(ans,i);
    	}
    	sort(c+1,c+size+1); 
    	size = unique(c+1,c+size+1)-(c+1); //离散化
    	sort(s,s+n+1,cmp);//按a排序,保证a是偏序
    	memset(tr,0x3f,sizeof(tr));
    	for(int i = 0; i <= n; i++){
    		int pos = lower_bound(c+1, c+size+1,s[i].b)-c; //找到相对位置
    		ans = max(ans, s[i].id - query(pos)); //查询比该值小的最小的位置
    		modify(pos, s[i].id); //当前位置进行更新
    	} 
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    fetch
    创建Vue实例传入的option
    Text and Binary modes
    daemon_int
    http 协议 c++代码 获取网页
    asp.net mvc 5 初体验
    win32 音视频相关 api
    setuid和seteuid
    用0x077CB531计算末尾0的个数
    webservice gsoap 小记
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13507391.html
Copyright © 2020-2023  润新知