• SPOJ 1557 GSS2


    都说这题是 GSS 系列中最难的,今天做了一下,名副其实
    首先你可以想到各种各样的在线乱搞想法,线段树,主席树,平衡树,等等,但发现都不太可行。
    注意到题目也没有说强制在线,因此可以想到离线地去解决这道题。
    我们把询问按照右端点从小到大排序。假设当前询问的右端点为 (i)
    定义 (s_j)([j,i]) 中不重复数字的和。我们建一棵线段树维护 (s_j) 的最大值。
    这样修改起来就比较自然了,当右端点从 (i-1) 变到 (i) 的时候,记 (a_i) 上一次出现的位置为 (k),那么这个 (a_i) 只会对 (s_{k+1},s_{k+2},dots,s_i) 产生贡献,也就是说我们在线段树上 ([k+1,i]) 位置上的数 (+a_i)
    询问也比较容易。询问 ((l,i)) 的答案就是 (s_l,s_{l+1},dots,s_i) 的历史最大值。
    这样原题就转化为一道看起来比较可做的 DS 了,要你维护一个序列,支持:

    • 区间加
    • 区间历史最大值

    之前写过一道类似的题题号什么我忘了,可现在忘了怎么做了/kk,只好看题解再推一遍。
    线段树区间维护四个东西 (mx,hmx,lz,hlz) 表示最大值,历史最大值,区间加标记,历史最大区间加标记(历史出现过的懒标记的最大值)。
    上推操作就不用说了吧,直接对 (mx,hmx)(max)。。。。。。
    区间加上一个值 (v),那么最大值肯定也会加上 (v),历史最大值就和当前最大值取 (max),懒标记也同理。
    最复杂的就是如何下传标记。
    例如我们现在有一段操作序列 (+1-3+4-2-1+5-2),那么此时懒标记为 (+2),历史最大懒标记为 (+4)(+1-3+4-2-1+4))。
    然后它的儿子当前最大值为 (2),历史最大值为 (3),当前懒标记为 (-1),历史最大懒标记为 (+1)
    那么:

    • (mx) 显然直接加上父亲的懒标记即可,(2+1-3+4-2-1+5-2=2+2=4)
    • (hmx) 拿当前最大值 (2) 加上历史最大懒标记 (+4)(2+1-3-4-2-1+5=6)),与原来历史最大值 (3) 比较。
    • (lz) 也是直接加上父亲的 (lz) 即可,(-1+2=+1)
    • (hlz) 也拿当前最大懒标记加上历史最大懒标记 (+4)(-1+1-3-4-2-1+5=+3)),与原来历史最大懒标记 (+1) 比较。

    最后,重中之重,下放懒标记的顺序一定要注意。

    /*
    Contest: -
    Problem: SP1557
    Author: tzc_wk
    Time: 2020.8.8
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define fi			first
    #define se			second
    #define fz(i,a,b)	for(int i=a;i<=b;i++)
    #define fd(i,a,b)	for(int i=a;i>=b;i--)
    #define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
    #define all(a)		a.begin(),a.end()
    #define fill0(a)	memset(a,0,sizeof(a))
    #define fill1(a)	memset(a,-1,sizeof(a))
    #define fillbig(a)	memset(a,0x3f,sizeof(a))
    #define fillsmall(a) memset(a,0xcf,sizeof(a))
    #define y1			y1010101010101
    #define y0			y0101010101010
    #define int long long
    typedef pair<int,int> pii;
    inline int read(){
    	int x=0,neg=1;char c=getchar();
    	while(!isdigit(c)){
    		if(c=='-') neg=-1;
    		c=getchar();
    	}
    	while(isdigit(c)) x=x*10+c-'0',c=getchar();
    	return x*neg;
    }
    int n=read(),m,a[100005],ans[100005];
    struct _query{
    	int l,r,id;
    	friend bool operator <(_query a,_query b){
    		return a.r<b.r;
    	}
    } q[100005];
    struct node{
    	int l,r,mx,hmx,lz,hlz;
    } s[100005<<2];
    inline void pushup(int k){
    	s[k].mx=max(s[k<<1].mx,s[k<<1|1].mx);
    	s[k].hmx=max(s[k<<1].hmx,s[k<<1|1].hmx);
    }
    inline void build(int k,int l,int r){
    	s[k].l=l;s[k].r=r;
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    }
    inline void pushdown(int k){
    	s[k<<1].hmx=max(s[k<<1].hmx,s[k<<1].mx+s[k].hlz);
    	s[k<<1|1].hmx=max(s[k<<1|1].hmx,s[k<<1|1].mx+s[k].hlz);
    	s[k<<1].mx+=s[k].lz;
    	s[k<<1|1].mx+=s[k].lz;
    	s[k<<1].hlz=max(s[k<<1].hlz,s[k<<1].lz+s[k].hlz);
    	s[k<<1|1].hlz=max(s[k<<1|1].hlz,s[k<<1|1].lz+s[k].hlz);
    	s[k<<1].lz=s[k<<1].lz+s[k].lz;
    	s[k<<1|1].lz=s[k<<1|1].lz+s[k].lz;
    	s[k].lz=s[k].hlz=0;
    }
    inline void add(int k,int l,int r,int x){
    	if(l<=s[k].l&&s[k].r<=r){
    		s[k].mx+=x;s[k].hmx=max(s[k].hmx,s[k].mx);
    		s[k].lz+=x;s[k].hlz=max(s[k].hlz,s[k].lz);
    		return;
    	}
    	pushdown(k);
    	int mid=(s[k].l+s[k].r)>>1;
    	if(r<=mid) add(k<<1,l,r,x);
    	else if(l>mid) add(k<<1|1,l,r,x);
    	else add(k<<1,l,mid,x),add(k<<1|1,mid+1,r,x);
    	pushup(k);
    }
    inline int query(int k,int l,int r){
    	if(l<=s[k].l&&s[k].r<=r){
    		return s[k].hmx;
    	}
    	pushdown(k);
    	int mid=(s[k].l+s[k].r)>>1;
    	if(r<=mid) return query(k<<1,l,r);
    	else if(l>mid) return query(k<<1|1,l,r);
    	else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
    }
    map<int,int> mp;
    signed main(){
    	fz(i,1,n) a[i]=read();
    	m=read();fz(i,1,m) q[i].l=read(),q[i].r=read(),q[i].id=i;
    	sort(q+1,q+m+1);
    	build(1,1,n);
    	int cur=1;
    	fz(i,1,n){
    		add(1,mp[a[i]]+1,i,a[i]);mp[a[i]]=i;
    		while(cur<=m&&q[cur].r<=i){
    			ans[q[cur].id]=query(1,q[cur].l,q[cur].r);cur++;
    		}
    	}
    	fz(i,1,m) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Struts2之页面取得当前actionName
    Javascript跳转页面和打开新窗口等方法
    数据集+树的一种最简单高效的算法
    TRzCheckTree的使用
    FASTSCRIPT脚本实现多国语言
    econtrol form designer添加三方控件
    内存管理六
    内存管理五
    程序启动时只显示登录窗体
    多标签主界面使用TRzPageControl
  • 原文地址:https://www.cnblogs.com/ET2006/p/SPOJ-1557.html
Copyright © 2020-2023  润新知