BZOJ 4826: [Hnoi2017]影魔
4826: [Hnoi2017]影魔
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 212 Solved: 114
[Submit][Status][Discuss]
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
HINT
Source
分析:
我们考虑每个值作为区间最大值的时候,可以产生的合法点对的贡献...
考虑对于每个点预处理出来$l[i]$和$r[i]$,分别表示$i$左边第一个比$a[i]$大的位置和右边第一个比$a[i]$大的位置...那么区间$[l[i]+1,r[i]-1]$代表的是极大的以$a[i]$为最大值的区间...
那么点对$(l[i],r[i])$的贡献就是$p1$,$(l[i],i+1~r[i]-1)$和$(l[i]+1~i-1,r[i])$的贡献为$p2$,其他点对的贡献就是$0$了...
欸,这就是一个区间加区间询问的问题...考试的时候写的在线,用可持久化线段树维护区间的和...但是考完发现可以离线用线段树维护...
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=200000+5,maxm=8000000+5; int n,m,p1,p2,top,a[maxn],lef[maxn],rig[maxn],stk[maxn]; long long ans; struct M{ int tot,ls[maxm],rs[maxm],root[maxn*3]; long long sum[maxm],add[maxm]; inline void init(void){ tot=0; memset(sum,0,sizeof(sum)); memset(root,0,sizeof(root)); } inline void change(int l,int r,int x,int &y,int L,int R,int val){ if(L>R) return; y=++tot;sum[y]=sum[x]+(R-L+1)*val;add[y]=add[x]; ls[y]=ls[x];rs[y]=rs[x]; if(l==L&&R==r){ add[y]+=val;return; } int mid=l+r>>1; if(R<=mid) change(l,mid,ls[x],ls[y],L,R,val); else if(L>mid) change(mid+1,r,rs[x],rs[y],L,R,val); else change(l,mid,ls[x],ls[y],L,mid,val),change(mid+1,r,rs[x],rs[y],mid+1,R,val); } inline long long query(int l,int r,int x,int y,int L,int R){ if(l==L&&r==R) return sum[y]-sum[x]; int mid=l+r>>1;long long ans=1LL*(R-L+1)*(add[y]-add[x]); if(R<=mid) ans+=query(l,mid,ls[x],ls[y],L,R); else if(L>mid) ans+=query(mid+1,r,rs[x],rs[y],L,R); else ans+=query(l,mid,ls[x],ls[y],L,mid)+query(mid+1,r,rs[x],rs[y],mid+1,R); return ans; } }tr1,tr2; struct N{ int cnt,l[maxn*3],r[maxn*3],hd[maxn],val[maxn*3],nxt[maxn*3]; inline void init(void){ memset(hd,-1,sizeof(hd));cnt=0; } inline void add(int x,int L,int R,int v){ // cout<<x<<" "<<L<<" "<<R<<" "<<v<<endl; l[cnt]=L,r[cnt]=R,val[cnt]=v,nxt[cnt]=hd[x],hd[x]=cnt++; } }tree1,tree2; inline int read(void){ char ch=getchar();int x=0; while(!(ch>='0'&&ch<='9')) ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } signed main(void){ // freopen("sf.in","r",stdin); // freopen("sf.out","w",stdout); n=read(),m=read(),p1=read(),p2=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++){ while(top&&a[stk[top]]<a[i]) rig[stk[top]]=i,top--; stk[++top]=i; } while(top) rig[stk[top--]]=n+1; for(int i=n;i>=1;i--){ while(top&&a[stk[top]]<a[i]) lef[stk[top]]=i,top--; stk[++top]=i; } while(top) lef[stk[top--]]=0; tree1.init();tree2.init(); for(int i=1;i<=n;i++){ tree1.add(lef[i],rig[i],rig[i],p1); if(i+1<=rig[i]-1) // cout<<"L: ", tree1.add(lef[i],i+1,rig[i]-1,p2); if(lef[i]+1<=i-1) // cout<<"R: ", tree2.add(rig[i],lef[i]+1,i-1,p2); } // puts("finish prework"); tr1.init();tr2.init(); for(int x=1;x<=n;x++){ tr1.root[x]=tr1.root[x-1]; for(int i=tree1.hd[x];i!=-1;i=tree1.nxt[i]) // cout<<"L: "<<x<<" "<<tree1.l[i]<<" "<<tree1.r[i]<<" "<<tree1.val[i]<<endl, tr1.change(1,n,tr1.root[x],tr1.root[x],max(1,tree1.l[i]),min(n,tree1.r[i]),tree1.val[i]); } for(int x=n;x>=1;x--){ tr2.root[x]=tr2.root[x+1]; for(int i=tree2.hd[x];i!=-1;i=tree2.nxt[i]) // cout<<"R: "<<x<<" "<<tree2.l[i]<<" "<<tree2.r[i]<<" "<<tree2.val[i]<<endl, tr2.change(1,n,tr2.root[x],tr2.root[x],max(1,tree2.l[i]),min(n,tree2.r[i]),tree2.val[i]); } for(int i=1,x,y;i<=m;i++){ x=read(),y=read();ans=(y-x)*p1; ans+=tr1.query(1,n,tr1.root[x-1],tr1.root[y],x,y); ans+=tr2.query(1,n,tr2.root[y+1],tr2.root[x],x,y); printf("%lld\n",ans); } // fclose(stdin);fclose(stdout); return 0; }
By NeighThorn