bzoj4540: [Hnoi2016]序列
4540: [Hnoi2016]序列
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1266 Solved: 594
[Submit][Status][Discuss]
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
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5
Sample Output
28
17
11
11
17
17
11
11
17
HINT
1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9
题解
这题一直没过今天发现单调栈写错了……
首先我们找出L[i],R[i]表示[L[i],i]和[i,R[i]都是比a[i]大的数,且a[L[i]-1]和a[R[i]+1]都要比a[i]大,这样左端点在[L[i],i],右端点在[i,R[i]]的区间都是以a[i]为最小值。也就是可以认为在二维平面上x坐标是[L[i],i]y坐标是[i,R[i]]的点权值都是a[i],而我们查询的实际上就是二维平面上[l,r][l,r]的矩形权值和。
L[i]和R[i]可以一遍单调栈轻松求出来。这样剩下的就是一个矩形加矩形求和的问题了,当然可以主席树来搞,但是觉得写的麻烦的我用了奇怪的办法……
首先把询问拆成在(r处询问(l,r))-(l-1处询问(l,r)),这样询问就是两个求前缀和的操作。用一条扫描线扫过去,矩形拆成加入和删除的删除(l1,l2,r2,+w),(r1+1,l2,r2,-w)。用一颗线段树(sum1)维护当前扫描线上的权值,假如当前扫描线在i的位置,有询问(l,r),那么首先计算x=sum1(L,R)*(i+1)的值,但是我们发现这样的话,假如矩形加事件发生在l1那么就会多算(1,l1)的部分。同时,如果一个矩形已经结束,我们会少算(l1,r1)的部分。这样我们可以再维护一颗线段树,事件(pos,l,r,w),每次加的权值是pos*w,最后把x-sum2(L,R)就行了。
代码比较丑……主要是这个思想对吧……
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define inf 1000000001 7 using namespace std; 8 const int N=200085; 9 long long F[4*N],Tag[4*N],f[4*N],tag[4*N]; 10 long long ans[N]; 11 long long a[N],st[N],L[N],R[N]; 12 struct opr{int id,l,r,ps,dd;}op[2*N]; 13 struct mar{int l,r,dd,ps;long long w;}data[2*N]; 14 int n,m,l,r,tt,tot; 15 inline long long read() 16 { 17 int x=0,f=1;char ch=getchar(); 18 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 19 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 20 return x*f; 21 } 22 bool cmp1(mar a,mar b) 23 { 24 return a.ps<b.ps; 25 } 26 bool cmp2(opr a,opr b) 27 { 28 return a.ps<b.ps; 29 } 30 void INS(int i,int l,int r,int ll,int rr,long long w) 31 { 32 if((ll<=l)&&(r<=rr)) 33 { 34 Tag[i]+=w;F[i]+=w*(long long)(r-l+1);return; 35 } 36 int mid=(l+r)/2; 37 if(ll<=mid)INS(i*2,l,mid,ll,rr,w);if(mid+1<=rr)INS(i*2+1,mid+1,r,ll,rr,w); 38 F[i]=Tag[i]*(long long)(r-l+1)+F[i*2]+F[i*2+1]; 39 } 40 void ins(int i,int l,int r,int ll,int rr,long long w) 41 { 42 if((ll<=l)&&(r<=rr)) 43 { 44 tag[i]+=w;f[i]+=w*(long long)(r-l+1);return; 45 } 46 int mid=(l+r)/2; 47 if(ll<=mid)ins(i*2,l,mid,ll,rr,w);if(mid+1<=rr)ins(i*2+1,mid+1,r,ll,rr,w); 48 f[i]=tag[i]*(long long)(r-l+1)+f[i*2]+f[i*2+1]; 49 } 50 long long ASK(int i,int l,int r,int ll,int rr) 51 { 52 if((ll<=l)&&(r<=rr))return F[i]; 53 int mid=(l+r)/2;long long tmp=Tag[i]*(long long)(min(rr,r)-max(ll,l)+1); 54 if(ll<=mid)tmp+=ASK(i*2,l,mid,ll,rr);if(mid+1<=rr)tmp+=ASK(i*2+1,mid+1,r,ll,rr); 55 return tmp; 56 } 57 long long ask(int i,int l,int r,int ll,int rr) 58 { 59 if((ll<=l)&&(r<=rr))return f[i]; 60 int mid=(l+r)/2;long long tmp=tag[i]*(long long)(min(rr,r)-max(ll,l)+1); 61 if(ll<=mid)tmp+=ask(i*2,l,mid,ll,rr);if(mid+1<=rr)tmp+=ask(i*2+1,mid+1,r,ll,rr); 62 return tmp; 63 } 64 int main() 65 { 66 int n=read(),m=read(); 67 for(int i=1;i<=n;i++)a[i]=read(); 68 a[0]=-inf; 69 int top=0;st[0]=0; 70 for(int i=1;i<=n;i++) 71 { 72 while(a[st[top]]>=a[i]){L[st[top]]=st[top-1]+1;R[st[top]]=i-1;top--;} 73 st[++top]=i; 74 } 75 while(top){L[st[top]]=st[top-1]+1;R[st[top]]=n;top--;} 76 for(int i=1;i<=n;i++) 77 { 78 if(L[i]<=R[i]) 79 { 80 data[++tt].w=a[i];data[tt].l=L[i];data[tt].r=i;data[tt].ps=i;data[tt].dd=1; 81 data[++tt].w=a[i];data[tt].l=L[i];data[tt].r=i;data[tt].ps=R[i]+1;data[tt].dd=-1; 82 } 83 } 84 sort(data+1,data+tt+1,cmp1); 85 for(int i=1;i<=m;i++) 86 { 87 l=read();r=read(); 88 op[++tot].id=i;op[tot].l=l;op[tot].r=r;op[tot].ps=r;op[tot].dd=1; 89 op[++tot].id=i;op[tot].l=l;op[tot].r=r;op[tot].ps=l-1;op[tot].dd=-1; 90 } 91 sort(op+1,op+tot+1,cmp2);int j=1; 92 for(int i=1;i<=tot;i++) 93 { 94 while((data[j].ps<=op[i].ps)&&(j<=tt)) 95 { 96 long long now=data[j].ps;long long w=now*(long long)data[j].w; 97 INS(1,1,n,data[j].l,data[j].r,w*data[j].dd); 98 ins(1,1,n,data[j].l,data[j].r,data[j].w*data[j].dd); 99 j++; 100 } 101 long long w; 102 w=ask(1,1,n,op[i].l,op[i].r)*(long long)(op[i].ps+1); 103 w=w-ASK(1,1,n,op[i].l,op[i].r); 104 ans[op[i].id]+=w*op[i].dd; 105 } 106 for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); 107 return 0; 108 }