• SP1557 GSS2


    题目链接

    题意

    给出长度为(n)的序列(a_i)(q) 次询问,求最大子段和,相同的数只算一次

    (1 ≤ n,q≤ 100000)

    (-100000≤a_i≤100000)

    分析

    没有修改操作,考虑离线处理

    正序扫描序列加入每个元素,并在线段树中的每个叶子节点(i)维护区间([i,j])去掉重复元素后的区间和((j)为目前扫描到的位置)

    如何去重

    定义(pre[i])表示(i)上一次出现的位置

    如果一个元素(a_i)(pre[a_i])的位置出现过了,那就只在区间([pre[a_i]+1,i])中加入它(区间加),相当于自动完成了去重

    如何处理询问

    把每个询问离线下来,按右端点排序,对于每个询问([l,r]),在加入(a_r)后查询(max(a_i+a_{i+1}...+a_{j-1}+a_j)) (l≤i≤j≤r)(区间查询),既区间([l,r])中的历史最大值

    如何维护历史最大值

    线段树中的下放操作有较大的"时间差",直接和当前值取max肯定不行

    于是我们在线段树中维护四个值:最大去重和, 历史最大去重和, 历史最大标记, 目前标记

    下放一个节点时,用该节点的历史最大标记去更新子节点的历史最大去重和和历史最大标记即可

    (code)

    #include<bits/stdc++.h>
    using namespace std;
    #define lson node<<1
    #define rson node<<1|1
    const int MAXN = 100010;
    #define int long long
    inline int read(){
    	int X=0; bool flag=1; char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
    	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
    	if(flag) return X;
    	return ~(X-1);
    }
    int n,m,a[MAXN],pre[20*MAXN],ans[MAXN];
    struct query{
    	int l,r,id;
    }q[MAXN];
    bool cmp(query a,query b){
    	return a.r<b.r;
    }
    struct st{
    	int max,hismax;
    	int tag,histag;
    }tree[MAXN<<2];
    void pushup(int node){
    	tree[node].max = max(tree[lson].max,tree[rson].max);
    	tree[node].hismax = max(tree[lson].hismax,tree[rson].hismax);
    }
    void pushdown(int node,int fa){
    	tree[node].hismax = max(tree[node].hismax,tree[fa].histag+tree[node].max);//更新历史最大值和历史最大tag
    	tree[node].histag = max(tree[node].histag,tree[fa].histag+tree[node].tag);
    	tree[node].max+=tree[fa].tag;
    	tree[node].tag+=tree[fa].tag;
    }
    void PUSHDOWN(int node){
    	if(!tree[node].tag) return;
    	pushdown(lson,node);
    	pushdown(rson,node);
    	tree[node].histag = tree[node].tag = 0;
    } 
    void modify(int node,int l,int r,int x,int y,int val){
    	if(x<=l&&y>=r){
    		tree[node].max+=val,tree[node].tag+=val;
    		tree[node].hismax = max(tree[node].hismax,tree[node].max);
    		tree[node].histag = max(tree[node].histag,tree[node].tag);
    		return;
    	}
    	PUSHDOWN(node);
    	int mid = (l+r)>>1;
    	if(x<=mid) modify(lson,l,mid,x,y,val);
    	if(y>mid) modify(rson,mid+1,r,x,y,val);
    	pushup(node);
    }
    int query(int node,int l,int r,int x,int y){
    	if(x<=l&&y>=r){
    		return tree[node].hismax;
    	}
    	PUSHDOWN(node);
    	int mid = (l+r)>>1;
    	if(y<=mid) return query(lson,l,mid,x,y);
    	if(x>mid) return query(rson,mid+1,r,x,y);
    	return max(query(lson,l,mid,x,y),query(rson,mid+1,r,x,y));
    }
    signed main(){
    	n = read();
    	for(int i=1;i<=n;i++) a[i] = read();
    	m = read();
    	for(int i=1;i<=m;i++){
    	    q[i].l = read(),q[i].r = read();
    	    q[i].id = i;
    	}
    	sort(q+1,q+1+m,cmp);
    	int j = 1;
    	for(int i=1;i<=n;i++){
    		modify(1,1,n,pre[a[i]+100000]+1,i,a[i]);
    		pre[a[i]+100000] = i;
    		while(i==q[j].r&&j<=m) ans[q[j].id] = query(1,1,n,q[j].l,q[j].r),j++;
    	}
    	for(int i=1;i<=m;i++){
    		printf("%lld
    ",ans[i]);
    	} 
    }
    
  • 相关阅读:
    AI听说读写
    C#文件夹检测与创建
    全球唯一标识符 System.Guid.NewGuid().ToString();
    mssql不允许删表方法
    SQLServer(MSSQL)、MySQL、SQLite、Access相互迁移转换工具
    sql语句精剪数据长度函数substring(string,int,int)
    代码生成工具
    [Java123] POI CellType 数据类型
    FRM二级备考感想
    【Java123】XML与JSON互相转化
  • 原文地址:https://www.cnblogs.com/xcxc82/p/14122679.html
Copyright © 2020-2023  润新知