• BZOJ2482: [Spoj1557] Can you answer these queries II


    没睡醒的时候做这个题是最致命的  看上去能做 但是没有仔细分析就会掉进坑里 言归正传

    题解: 这个题 很明显离线做 对于每个位置由线段树维护以x做起点[x,n]位置上的历史最大值 似乎吉利爷论文上有写  我们可以通过维护两个push操作直接的历史增量的峰值 来维护答案 我们可以这样分析 我们知道了rt的历史增量的峰值 那么rt<<1和rt<<1|1历史增量的峰值可以维护 然后我们可以通过增量维护历史最大值即可

    #include <bits/stdc++.h>
    const int MAXN=1e5+10;
    #define ll long long
    const ll inf=1e18;
    using namespace std;
    typedef struct node{
    	ll ans,sum,vtag,tag;
    }node;
    node d[MAXN<<2];
    vector<int>vec;
    int n,m;
    int a[MAXN],b[MAXN];
    void push(int rt){
    	d[rt<<1].ans=max(d[rt<<1].ans,d[rt<<1].sum+d[rt].vtag);
    	d[rt<<1|1].ans=max(d[rt<<1|1].ans,d[rt<<1|1].sum+d[rt].vtag);
    	d[rt<<1].sum+=d[rt].tag;d[rt<<1|1].sum+=d[rt].tag;
    	d[rt<<1].vtag=max(d[rt<<1].vtag,d[rt<<1].tag+d[rt].vtag);
    	d[rt<<1|1].vtag=max(d[rt<<1|1].vtag,d[rt<<1|1].tag+d[rt].vtag);
    	d[rt<<1].tag+=d[rt].tag;d[rt<<1|1].tag+=d[rt].tag;
    	d[rt].vtag=0;d[rt].tag=0;
    }
    void up(int x){
    	d[x].sum=max(d[x<<1].sum,d[x<<1|1].sum);
    	d[x].ans=max(d[x<<1].ans,d[x<<1|1].ans);
    }
    void update(int rt,int l,int r,int ql,int qr,int vul){
    	if(ql<=l&&r<=qr){
    		d[rt].sum+=vul;d[rt].tag+=vul;
    		d[rt].vtag=max(d[rt].vtag,d[rt].tag);
    		d[rt].ans=max(d[rt].ans,d[rt].sum);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	push(rt);
    	if(ql<=mid)update(rt<<1,l,mid,ql,qr,vul);
    	if(qr>mid)update(rt<<1|1,mid+1,r,ql,qr,vul);
    	up(rt);
    }
    ll ans;
    void querty(int rt,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr){ans=max(ans,d[rt].ans);return ;}
    	int mid=(l+r)>>1;
    	push(rt);
    	if(ql<=mid)querty(rt<<1,l,mid,ql,qr);
    	if(qr>mid)querty(rt<<1|1,mid+1,r,ql,qr);
    	up(rt);
    }
    typedef struct Node{
    	int l,r,id;
    	friend bool operator<(Node aa,Node bb){return aa.r<bb.r;}
    }Node;
    Node que[MAXN];int pre[MAXN],vis[MAXN];
    ll ans1[MAXN];
    int main(){
    	scanf("%d",&n);
    	memset(pre,0,sizeof(pre));
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]),vec.push_back(a[i]);
    	sort(vec.begin(),vec.end());
    	int sz=unique(vec.begin(),vec.end())-vec.begin();
    	for(int i=1;i<=n;i++)b[i]=lower_bound(vec.begin(),vec.begin()+sz,a[i])-vec.begin()+1;
    	for(int i=1;i<=n;i++){vis[i]=pre[b[i]]+1;pre[b[i]]=i;}
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)scanf("%d%d",&que[i].l,&que[i].r),que[i].id=i;
    	sort(que+1,que+m+1);int k=1;
    	for(int i=1;i<=m;i++){
    		while(k<=n&&que[i].r>=k){update(1,1,n,vis[k],k,a[k]);k++;}
    		//cout<<d[1].ans<<" "<<d[1].sum<<endl;
    		ans=0;querty(1,1,n,que[i].l,que[i].r);ans1[que[i].id]=ans;
    	}
    	for(int i=1;i<=m;i++)printf("%lld
    ",ans1[i]);
    	return 0;
    }
    

    2482: [Spoj1557] Can you answer these queries II

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 280  Solved: 149
    [Submit][Status][Discuss]

    Description

    给定n个元素的序列。
    给出m个询问:求l[i]~r[i]的最大子段和(可选空子段)。
    这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次。
    比如:1,2,3,2,2,2出现了3次,但只算一次,于是这个序列的和是1+2+3=6。

    Input

     

    第一行一个数n。
    第二行n个数,为给定的序列,这些数的绝对值小于等于100000。
    第三行一个数m。
    接下来m行,每行两个数,l[i],r[i]。

    Output

    M行,每行一个数,为每个询问的答案。

    Sample Input

    9
    4 -2 -2 3 -1 -4 2 2 -6
    3
    1 2
    1 5
    4 9


    Sample Output


    4
    5
    3

    HINT

    【数据说明】

    30%:1 <= n, m <= 100

    100%:1 <= n, m <= 100000

  • 相关阅读:
    [翻译]跟我一起边译边学之Linux:目录
    [翻译]跟我一起边译边学之Linux:致谢 Acknowledgments
    计算机图形学资源收集01
    计算机图形学资源收集02
    计算机图形学资源收集04
    计算机图形学资源收集03
    C#二十几种设计模式事例下载(源码)
    在WinForm应用程序中嵌入WPF控件
    .net网站与Winform窗体的数据交互(JS调用Winform后台方法实现)
    C#调用rar.exe解压一个rar文件
  • 原文地址:https://www.cnblogs.com/wang9897/p/9477537.html
Copyright © 2020-2023  润新知