• BZOJ4540: [Hnoi2016]序列


    BZOJ4540: [Hnoi2016]序列

    Description

    给定长度为n的序列:a1,a2,…,an,记为a[1:n]。

    类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-1,ar

    若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列。

    现在有q个询问,每个询问给定两个数l和r,1≤l≤r≤n,求a[l:r]的不同子序列的最小值之和。

    例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有6个子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这6个子序列的最小值之和为5+2+4+2+2+2=17。

    Input

    输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。

    接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i个元素的值。

    接下来q行,每行包含两个整数l和r,代表一次询问。

    Output

    对于每次询问,输出一行,代表询问的答案。

    Sample Input

    5 5
    5 2 4 1 3
    1 5
    1 3
    2 4
    3 5
    2 5

    Sample Output

    28
    17
    11
    11
    17

    HINT

    1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9


    题解Here!
    字符串做得要吐了,于是又回来搞大力数据结构。。。
    然后发现还是数据结构好写555。。。
    这个题反正$RMQ$跑不了。
    然后就是怎么求子区间的和了。
    没有强制在线,我们可以拿出区间神器——莫队
    莫队的难点就在于怎么由区间$[l,r]$推出$[l,r+1]$。
    考虑他们之间的增加量就是新增的区间$[l,r+1],[l+1,r+1],[l+2,r+1],...,[r+1,r+1]$的最小值之和。
    一共$r-l+2$个区间。
    如果我们知道区间$[l,r+1]$的最小值位置为$pos$,那么左端点在区间$[l,pos]$之前的区间答案都是$val[pos]$。
    对答案的贡献就是$val[pos] imes (pos-l+1)$。
    至于$pos$怎么求,当然用$O(1)$的$ST$表啦。。。
    只不过$ST$表维护的是最小值的位置。
    再考虑剩下的左端点在$[pos+1,r+1]$之间的区间。
    这里引入一个类似前缀和的东西。
    我们用$front[i]$表示$i$左边第一个比$val[i]$小的数的位置,$next[i]$表示右边。
    这个过程显然可以用单调栈$O(n)$预处理。
    然后开2个数组$maxl,maxr$。
    $maxl[i]$表示$[1,i]$的贡献,那么就有:$maxl[i]=maxl[front[i]]+(i-front[i])*val[i]$
    $maxr$同理。
    这样,我们就可以在$O(1)$时间内转移了。
    那么,从$[l,r]$到$[l,r-1]$呢?
    我们只要减去$[l,r-1]->[l,r]$的贡献即可。
    从$[l,r]$到$[l+1,r]$与从$[l,r]$到$[l-1,r]$就利用对称性求解即可。
    然后我们就可以愉快地跑莫队了。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #define MAXN 100010
    using namespace std;
    int n,m;
    int val[MAXN],f[MAXN][30],front[MAXN],next[MAXN];
    long long ans[MAXN],maxl[MAXN],maxr[MAXN];
    struct node{
    	int l,r,id;
    }que[MAXN];
    struct Stack{
        int value[MAXN],numtop;
        Stack(){
            memset(value,0,sizeof(value));
            numtop=0;
        }
        inline void push(int x){value[++numtop]=x;}
        inline void pop(){value[numtop--]=0;}
        inline int top(){return value[numtop];}
        inline int empty(){return (numtop==0?1:0);}
    }stack;
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    bool cmp1(const node &x,const node &y){
    	return x.l<y.l;
    }
    bool cmp2(const node &x,const node &y){
    	if(x.r==y.r)return x.l<y.l;
    	return x.r<y.r;
    }
    void step(){
        for(int i=1;(1<<i)<=n;i++)
        for(int j=1;j+(1<<i)-1<=n;j++){
        	if(val[f[j][i-1]]>val[f[j+(1<<(i-1))][i-1]])f[j][i]=f[j+(1<<(i-1))][i-1];
        	else f[j][i]=f[j][i-1];
        }
    }
    int query(int l,int r){
        int k=0;
        while((1<<(k+1))<=r-l+1)k++;
    	if(val[f[l][k]]>val[f[r-(1<<k)+1][k]])return f[r-(1<<k)+1][k];
        return f[l][k];
    }
    void work(){
        int left=1,right=0;
    	long long s=0;
    	for(int i=1;i<=m;i++){
    		while(right<que[i].r)
    		{
    			right++;
    			int pos=query(left,right);
    			s+=(long long)val[pos]*(pos-left+1)+maxl[right]-maxl[pos];
    		}
    		while(que[i].l>left)
    		{
    			int pos=query(left,right);
    			s-=(long long)val[pos]*(right-pos+1)+maxr[left]-maxr[pos];
    			left++;
    		}
    		while(right>que[i].r)
    		{
    			int pos=query(left,right);
    			s-=(long long)val[pos]*(pos-left+1)+maxl[right]-maxl[pos];
    			right--;
    		}
    		while(que[i].l<left)
    		{
    			left--;
    		    int pos=query(left,right);
    		    s+=(long long)val[pos]*(right-pos+1)+maxr[left]-maxr[pos];
    		}
    		ans[que[i].id]=s;
    	}
    	for(int i=1;i<=m;i++)printf("%lld
    ",ans[i]);
    }
    void init(){
    	int nowi=1,nowj=0,d,x;
        n=read();m=read();
        for(int i=1;i<=n;i++){
            val[i]=read();
            f[i][0]=i;
        }
        step();
    	for(int i=1;i<=m;i++){
    		que[i].l=read();que[i].r=read();
    		que[i].id=i;
    	}
    	x=sqrt(n);
    	sort(que+1,que+m+1,cmp1);
    	while(nowi<=m){
    		nowj++;
    		d=nowi;
    		while(que[nowi].l<nowj*x&&nowi<=m)nowi++;
    		sort(que+d,que+nowi,cmp2);
    		if(nowj==x){
    			sort(que+d,que+m+1,cmp2);
    			break;
    		}
    	}
    	for(int i=1;i<=n;i++){
    	    for(;!stack.empty()&&val[i]<val[stack.top()];stack.pop())next[stack.top()]=i;
    	    front[i]=stack.top();
    	    stack.push(i);
    	}
    	for(;!stack.empty();stack.pop())next[stack.top()]=n+1;
    	for(int i=1;i<=n;i++)maxl[i]=maxl[front[i]]+(long long)val[i]*(i-front[i]);
    	for(int i=n;i>=1;i--)maxr[i]=maxr[next[i]]+(long long)val[i]*(next[i]-i);
    }
    int main(){
        init();
        work();
    	return 0;
    }
    
  • 相关阅读:
    414. Third Maximum Number 第三大的数字
    java 正则表达式
    将含有逻辑运算符的字符串解析为逻辑符号
    ora-01830:日期格式图片在转换整个输入字符串之前结束
    mysql的字符拼接
    oracle执行计划详解
    oracle获取执行计划及优缺点 详解
    kmp算法中的nextval实例解释
    kmp算法中的next数组实例解释
    哈夫曼实例解释(哈夫曼编码)
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9459962.html
Copyright © 2020-2023  润新知