【BZOJ4826】[Hnoi2017]影魔
Description
影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i<j)来说,若不存在 k[s](i<s<j)大于 k[i]或者 k[j],则会为影魔提供 p1 的攻击力(可理解为:当 j=i+1 时,因为不存在满足 i<s<j 的 s,从而 k[s]不存在,这时提供 p1 的攻击力;当 j>i+1 时,若max{k[s]|i<s<j}<=min{k[i],k[j]} , 则 提 供 p1 的 攻击 力 ); 另 一 种 情 况 , 令 c 为k[i+1],k[i+2],k[i+3]......k[j-1]的最大值,若 c 满足:k[i]<c<k[j],或者 k[j]<c<k[i],则会为影魔提供 p2 的攻击力,当这样的 c 不存在时,自然不会提供这 p2 的攻击力;其他情况的点对,均不会为影魔提供攻击力。影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间[a,b],1<=a<b<=n,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑 所有满足a<=i<j<=b 的灵魂对 i,j 提供的攻击力之和。顺带一提,灵魂的战斗力组成一个 1 到 n 的排列:k[1],k[2],...,k[n]。
Input
第一行 n,m,p1,p2
第二行 n 个数:k[1],k[2],...,k[n]
接下来 m 行,每行两个数 a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
1 <= n,m <= 200000;1 <= p1,p2 <= 1000
Output
共输出 m 行,每行一个答案,依次对应 m 个询问。
Sample Input
10 5 2 3
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
Sample Output
30
39
4
13
16
39
4
13
16
题解:用单调栈求出每个数左边和右边第一个比它大的数的位置,设其为l[i],r[i]。那么这样的点对:
(l[i],r[i]),(i,i+1)提供p1攻击力
(l[i]...i-1,r[i]),(l[i],i+1...r[i])提供p2攻击力
那么这就变成了在二维平面中,一些线段和点有权值,求矩形内的权值和。可以用扫描线解决(+区间修改树状数组)。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn=200010; typedef long long ll; int n,m,n1,n2,m1,top; int v[maxn],lm[maxn],rm[maxn],st[maxn]; ll p1,p2; ll ans[maxn]; struct sag { int sx,sl,sr,sv; }s1[maxn<<1],s2[maxn<<1]; struct QUERY { int qx,ql,qr,org,qv; }q[maxn<<1]; struct BIT { ll s[maxn]; void init(){memset(s,0,sizeof(s));} void updata(int x,ll val) { for(int i=x;i<=n;i+=i&-i) s[i]+=val; } ll query(int x) { ll ret=0; for(int i=x;i;i-=i&-i) ret+=s[i]; return ret; } }sa,sb; void modify(int x,ll val) { if(x<=0) return ; sa.updata(x,val),sb.updata(x,val*x); } ll ask(int x) { return (sa.query(n)-sa.query(x))*x+sb.query(x); } int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } bool cmps(sag a,sag b) { return a.sx<b.sx; } bool cmpq(QUERY a,QUERY b) { return a.qx<b.qx; } int main() { n=rd(),m=rd(),p1=rd(),p2=rd(); int i,j; for(i=1;i<=n;i++) v[i]=rd(); for(top=0,i=1;i<=n;i++) { while(top&&v[st[top]]<v[i]) rm[st[top--]]=i; lm[i]=st[top],st[++top]=i; } for(i=1;i<=n;i++) { if(lm[i]&&rm[i]) s1[++n1].sx=lm[i],s1[n1].sl=s1[n1].sr=rm[i],s1[n1].sv=p1; if(i<n) s2[++n2].sx=i+1,s2[n2].sl=s2[n2].sr=i,s2[n2].sv=p1; if(!rm[i]) rm[i]=n+1; if(lm[i]&&rm[i]>i+1) s1[++n1].sx=lm[i],s1[n1].sl=i+1,s1[n1].sr=rm[i]-1,s1[n1].sv=p2; if(rm[i]<=n&&lm[i]<i-1) s2[++n2].sx=rm[i],s2[n2].sl=lm[i]+1,s2[n2].sr=i-1,s2[n2].sv=p2; } sort(s1+1,s1+n1+1,cmps),sort(s2+1,s2+n2+1,cmps); for(i=1;i<=m;i++) { q[i].qx=q[i].ql=q[i+m].ql=rd(),q[i+m].qx=q[i].qr=q[i+m].qr=rd(); q[i].qx--,q[i].org=i=q[i+m].org=i,q[i].qv=-1,q[i+m].qv=1; } sort(q+1,q+2*m+1,cmpq); for(i=j=1;i<=2*m;i++) { if(!q[i].qx) continue; for(;j<=n1&&s1[j].sx<=q[i].qx;j++) modify(s1[j].sl-1,-s1[j].sv),modify(s1[j].sr,s1[j].sv); ans[q[i].org]+=q[i].qv*(ask(q[i].qr)-ask(q[i].ql-1)); } sa.init(),sb.init(); for(i=j=1;i<=2*m;i++) { if(!q[i].qx) continue; for(;j<=n2&&s2[j].sx<=q[i].qx;j++) modify(s2[j].sl-1,-s2[j].sv),modify(s2[j].sr,s2[j].sv); ans[q[i].org]+=q[i].qv*(ask(q[i].qr)-ask(q[i].ql-1)); } for(i=1;i<=m;i++) printf("%lld ",ans[i]); return 0; }