zoukankan      html  css  js  c++  java
  • 【bzoj4540】 Hnoi2016—序列

    http://www.lydsy.com/JudgeOnline/problem.php?id=4540 (题目链接)

    题意

      给出$n$个数的序列,$m$个询问,每次询问一段区间$[l,r]$,问$[l,r]$中的不同子序列的最小值之和。

    Solution

      右转题解→_→:jump

      处理处前缀和和后缀和以后,ST表维护区间最小值, 对于一段区间,求出它的区间最小值,跳$last$或者是$next$到此终止,我们就求出了终止位置。莫队转移过程脑补一下就就好了。

    细节

      LL

    代码

    // bzoj4540
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf (1ll<<60)
    #define MOD 1000000007
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=100010;
    int a[maxn],pos[maxn],next[maxn],last[maxn];
    int ST[maxn][30],Log[maxn],st[maxn],bin[30],n,m,top,block;
    LL prefix[maxn],suffix[maxn],ans[maxn],sum;
    struct ask {int l,r,id;}q[maxn];
    
    bool cmp(ask a,ask b) {return pos[a.l]==pos[b.l] ? a.r<b.r : pos[a.l]<pos[b.l];}
    int mina(int x,int y) {return a[x]>a[y] ? y : x;}
    
    int query(int l,int r) {
    	int k=Log[r-l+1];
    	return mina(ST[l][k],ST[r-bin[k]+1][k]);
    }
    void updater(int l,int r,int op) {
    	int mn=query(l,r);
    	sum+=(LL)op*(prefix[r]-prefix[mn]+(LL)a[mn]*(mn-l+1));
    }
    void updatel(int l,int r,int op) {
    	int mn=query(l,r);
    	sum+=(LL)op*(suffix[l]-suffix[mn]+(LL)a[mn]*(r-mn+1));
    }
    int main() {
    	bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
    	scanf("%d%d",&n,&m);block=(int)sqrt(n);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]),ST[i][0]=i;
    	for (int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    	for (int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
    	for (int i=1;i<=n;i++) {
    		while (top && a[st[top]]>a[i]) next[st[top--]]=i;
    		last[i]=st[top];st[++top]=i;
    	}
    	for (int i=1;i<=n;i++) prefix[i]=(LL)(i-last[i])*a[i]+prefix[last[i]];
    	for (int i=n;i>=1;i--) suffix[i]=(LL)(next[i]-i)*a[i]+suffix[next[i]];
    	for (int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
    	for (int j=1;j<=20;j++) 
    		for (int i=1;i+bin[j]<=n+1;i++)
    			ST[i][j]=mina(ST[i][j-1],ST[i+bin[j-1]][j-1]);
    	sort(q+1,q+1+m,cmp);sum=0;
    	for (int l=1,r=0,i=1;i<=m;i++) {
    		for (;r<q[i].r;r++) updater(l,r+1,1);
    		for (;l>q[i].l;l--) updatel(l-1,r,1);
    		for (;r>q[i].r;r--) updater(l,r,-1);
    		for (;l<q[i].l;l++) updatel(l,r,-1);
    		ans[q[i].id]=sum;
    	}
    	for (int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    psy & vr
    psy 2
    psy
    linux c中select使用技巧
    hostent h_addr_list
    gethostbyname() -- 用域名或主机名获取IP地址
    c_select 调用参数说明
    [NYOJ 737] 石子合并(一)
    [HDU 1059] Dividing
    [HDU 1789] Doing Homework again
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6422501.html
Copyright © 2011-2022 走看看