• SPOJ GSS2 Can you answer these queries II ——线段树


    【题目分析】

        线段树,好强!

        首先从左往右依次扫描,线段树维护一下f[]。f[i]表示从i到当前位置的和的值。

        然后询问按照右端点排序,扫到一个位置,就相当于查询区间历史最值。

        关于历史最值问题:

        标记是有顺序的,如果下方标记比较勤快,使得两个标记不会叠加,常数会很大,但是好写。

        发现标记随着层数的递增越来越古老,(否则就被下放了),所以维护历史最大更新和当前更新即可。

        好题!

    【代码】

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    
    #include <map>
    #include <set>
    #include <queue>
    #include <string>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    #define maxn 1000005
    #define inf 0x3f3f3f3f
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    
    void Finout()
    {
        #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("wa.txt","w",stdout);
        #endif
    }
    
    int Getint()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    const int buf=200005;
    int n,m,a[maxn],last[maxn],bac[maxn];
    struct Que{int l,r,id,ans;}q[maxn];
    
    struct Segment_Tree{
    	int L,R,C;
    	int old_mx[maxn],old_lazy[maxn];
    	int now_mx[maxn],now_lazy[maxn];
    	void init()
    	{
    		memset(old_mx,0,sizeof old_mx);
    		memset(now_mx,0,sizeof now_mx);
    		memset(old_lazy,0,sizeof old_lazy);
    		memset(now_lazy,0,sizeof now_lazy);
    	}
    	void update(int o,int l,int r)
    	{
    		old_mx[o]=max(old_mx[o<<1],old_mx[o<<1|1]);
    		now_mx[o]=max(now_mx[o<<1],now_mx[o<<1|1]);
    	}
    	void pushdown(int o,int l,int r)
    	{
    		old_lazy[o<<1]=max(old_lazy[o<<1],now_lazy[o<<1]+old_lazy[o]);
    		old_lazy[o<<1|1]=max(old_lazy[o<<1|1],now_lazy[o<<1|1]+old_lazy[o]);
    		
    		old_mx[o<<1]=max(old_mx[o<<1],now_mx[o<<1]+old_lazy[o]);
    		old_mx[o<<1|1]=max(old_mx[o<<1|1],now_mx[o<<1|1]+old_lazy[o]);
    		
    		now_lazy[o<<1]+=now_lazy[o];
    		now_lazy[o<<1|1]+=now_lazy[o];
    		
    		now_mx[o<<1]+=now_lazy[o];
    		now_mx[o<<1|1]+=now_lazy[o];
    		
    		now_lazy[o]=old_lazy[o]=0;
    	}
    	void add(int o,int l,int r)
    	{
    		if (L<=l&&r<=R)
    		{
    			old_lazy[o]=max(old_lazy[o],now_lazy[o]+=C);
    			old_mx[o]=max(old_mx[o],now_mx[o]+=C);
    			return ;
    		}
    		pushdown(o,l,r);
    		int mid=l+r>>1;
    		if (R<=mid) add(o<<1,l,mid);
    		else if (L>mid) add(o<<1|1,mid+1,r);
    		else add(o<<1,l,mid),add(o<<1|1,mid+1,r);
    		update(o,l,r);
    	}
    	int query(int o,int l,int r)
    	{
    		if (L<=l&&r<=R) return old_mx[o];
    		pushdown(o,l,r);
    		int mid=l+r>>1;
    		if (R<=mid) return query(o<<1,l,mid);
    		if (L>mid) return query(o<<1|1,mid+1,r);
    		else return max(query(o<<1,l,mid),query(o<<1|1,mid+1,r));
    	}
    }t;
    
    bool cmp1(Que x,Que y){return x.r<y.r;}
    bool cmp2(Que x,Que y){return x.id<y.id;}
    
    int main()
    {
        Finout();
    	n=Getint();
    	F(i,1,n) a[i]=Getint();
    	F(i,1,n)
    	{
    		last[i]=bac[a[i]+buf];
    		bac[a[i]+buf]=i;
    	}
    	m=Getint();
    	F(i,1,m)
    	{
    		q[i].l=Getint();
    		q[i].r=Getint();
    		q[i].id=i; 
    	}
    	sort(q+1,q+m+1,cmp1);
    	int h=0;
    	F(i,1,m)
    	{
    		while (h<q[i].r&&h<=n)
    		{
    			h++;
    			t.L=last[h]+1;
    			t.R=h;
    			t.C=a[h];
    //			printf("Add %d %d %d
    ",t.L,t.R,t.C);
    			t.add(1,1,n);
    		}
    		t.L=q[i].l;t.R=q[i].r;
    //		printf("Query %d %d for %d
    ",q[i].l,q[i].r,q[i].id);
    		q[i].ans=t.query(1,1,n);
    	}
    	sort(q+1,q+m+1,cmp2);
    	F(i,1,m) printf("%d
    ",q[i].ans);
    }
    

      

  • 相关阅读:
    CentOS yum 安装svn1.8
    js 替换掉汉字 和替换非汉字 比较时间JS
    PhpStorm 10 破解
    html中link的用法
    CSS3:nth-child()伪类选择器
    提示的小三角
    css 高度自适应
    <input type="file" />浏览时只显示指定文件类型
    MySQL查询表内重复记录
    扒站小工具
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6360288.html
Copyright © 2020-2023  润新知