zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    HDU 1124 Factorial
    hdu 1690 Bus System
    hdu 1113 Word Amalgamation
    POJ 2482 Stars in Your Window
    hdu 1385 ZOJ 1456 Minimum Transport Cost(经典floyd)
    hdu 1907 John
    VMware 虚拟机 安装 UBuntu 9.10 命令模式转换成窗口模试
    #pragma CODE_SEG __NEAR_SEG NON_BANKED详解
    Ubuntu 下Hadoop 伪分布式 hadoop0.20.2.tar.gz 的安装
    文件拷贝代码以及疑问
  • 原文地址:https://www.cnblogs.com/wang9897/p/9477537.html
Copyright © 2011-2022 走看看