BZOJ 4826: [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 个询问。
对于点 $i$,用单调栈求出左边和右边第一个大于 $i$ 的位置,记为 $l[i]$ 与 $r[i]$.
那么 $(l[i],r[i])$ 会产生 $p1$ 的贡献.
左端点为 $l[i]$,则如果右端点在 $[i+1,r-1]$ 的话都会产生 $p1$ 的贡献.
而右端点在 $r[i]$,左端点在 $[l+1,i-1]$ 都会产生 $p2$ 的贡献.
因为这个东西有一个端点是固定的,另一个区间是连续区间,所以可以用主席树来维护.
由于 $pushdown$ 函数比较麻烦,这里用的标记永久化.
#include <cstring> #include <cstdio> #include <stack> #include <string> #include <vector> #include <algorithm> #define N 200005 #define ll long long using namespace std; void setIO(string s) { string in=s+".in"; string out=s+".out"; freopen(in.c_str(),"r",stdin); // freopen(out.c_str(),"w",stdout); } int n,m,tp,edges; int p1,p2; int val[N]; int sta[N]; int L[N],R[N]; int hd[N]; int tot; int rtl[N]; int rtr[N]; struct Edge { int x; int l; int r; int v; int nex; }e[N*3]; struct node { int ls; int rs; ll tag; ll sum; }t[N*80]; void add(int u,int l,int r,int v) { e[++edges].nex=hd[u]; hd[u]=edges; e[edges].l=l; e[edges].r=r; e[edges].x=u; e[edges].v=v; } int newnode() { return ++tot; } int update(int x,int l,int r,int L,int R,int v) { if(L>R) { return x; } int now=newnode(); t[now]=t[x]; t[now].sum+=(ll)(min(r,R)-max(l,L)+1)*v; if(l>=L&&r<=R) { t[now].tag+=v; return now; } int mid=(l+r)>>1; if(L<=mid) { t[now].ls=update(t[x].ls,l,mid,L,R,v); } if(R>mid) { t[now].rs=update(t[x].rs,mid+1,r,L,R,v); } return now; } ll query(int x,int l,int r,int L,int R) { if(!x) { return 0; } if(l>=L&&r<=R) { return t[x].sum; } int mid=(l+r)>>1; ll re=(ll)t[x].tag*(min(r,R)-max(l,L)+1); if(L<=mid) { re+=query(t[x].ls,l,mid,L,R); } if(R>mid) { re+=query(t[x].rs,mid+1,r,L,R); } return re; } int main() { // setIO("input"); int i,j; scanf("%d%d%d%d",&n,&m,&p1,&p2); for(i=1;i<=n;++i) { scanf("%d",&val[i]); } for(i=1;i<=n;++i) { while(tp&&val[sta[tp]]<val[i]) { --tp; } L[i]=sta[tp]; sta[++tp]=i; } sta[tp=0]=n+1; for(i=n;i>=1;--i) { while(tp&&val[sta[tp]]<val[i]) { --tp; } R[i]=sta[tp]; sta[++tp]=i; } for(i=1;i<=n;++i) { add(L[i],R[i],R[i],p1); add(L[i],i+1,R[i]-1,p2); add(R[i],L[i]+1,i-1,p2); } // 向右 for(i=1;i<=n;++i) { rtl[i]=rtl[i-1]; for(j=hd[i];j;j=e[j].nex) { if(e[j].l>i) { rtl[i]=update(rtl[i],1,n,max(1,e[j].l),min(n,e[j].r),e[j].v); } } if(i!=n) { rtl[i]=update(rtl[i],1,n,i+1,i+1,p1); } } for(i=n;i>=1;--i) { rtr[i]=rtr[i+1]; for(j=hd[i];j;j=e[j].nex) { if(e[j].r<i) { rtr[i]=update(rtr[i],1,n,max(1,e[j].l),min(n,e[j].r),e[j].v); } } } while(m--) { int x,y; scanf("%d%d",&x,&y); ll ans=0ll; ans+=query(rtl[y],1,n,x,y); ans-=query(rtl[x-1],1,n,x,y); ans+=query(rtr[x],1,n,x,y); ans-=query(rtr[y+1],1,n,x,y); printf("%lld\n",ans); } return 0; }