BZOJ4826: [Hnoi2017]影魔
4826: [Hnoi2017]影魔
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 550 Solved: 300
[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
思路{
和去年的序列有点像啊...
对于一个点,单独计算其作为区间最大值的贡献,这也是一般的序列问题的套路。
对于单点$ i $,他所能作为一段区间内的最大值所能做出的贡献是什么,
找出左边第一个大于$K_i$的位置$L_i$,
右边第一个大于$K_i$的位置$R_i$;
一段区间做出的贡献,又十分自然想到了扫描线.
由于设二维平面上的点$( x , y ) $ 中$ y $值表示所代表的点.$x$值表示它所能够影响到的点。
$P_1$对应了点$ ( i , L_i ) $到$ ( i , R_i ) $的线段,
$P_2$对应了点$ ( L_i , i + 1 ) $到$ ( i , R_i - 1 ) $的线段,
$P_2$对应了点$ ( R_i , L_i + 1 ) $到$ ( R_i , i - 1 ) $的线段,
询问抽象成两条平行于 $ x $ 轴的线段,
每条线段左右端点即为所产生的贡献范围.那线段的左右端点和上下端点都是$L,R$了.
那么就是求询问所代表的区间内的权值和了!!
用扫描线+区间修改树状数组维护这个东西即可.
这么说来应该也可以用扫描线来解决去年的序列了.
}
#include<bits/stdc++.h> #define il inline #define RG register #define ll long long #define db double #define N 200010 #define lowbit (i&-i) using namespace std; int l[N],r[N],st[N],a[N],n,m,p1,p2; ll Ans[N]; namespace BIT{ ll t1[N],t2[N]; void clear(){memset(t1,0,sizeof(t1));memset(t2,0,sizeof(t2));} void add(int x,int y){ for(int i=x;i<=n;i+=lowbit)t1[i]+=y,t2[i]+=1ll*x*y; } void Insert(int l,int r,int num){ add(l,num),add(r+1,-num); } ll Query(int pos){ ll Sum(0); for(int i=pos;i;i-=lowbit)Sum+=(pos+1)*t1[i]-t2[i]; return Sum; } ll sum(int l,int r){ return Query(r)-Query(l-1); } } struct event{ int l,r,h,bel,val; event() {} event(int a,int b,int c,int d,int e):l(a),r(b),h(c),bel(d),val(e) {} }eve1[N*2],eve2[N*3];int tot1,tot2; bool comp(const event & a,const event & b){return a.h<b.h;} int main(){ scanf("%d%d%d%d",&n,&m,&p1,&p2); for(int i=1;i<=n;++i)scanf("%d",&a[i]); for(int i=1;i<=n;++i){ while(st[0]&&a[st[st[0]]]<a[i])r[st[st[0]--]]=i; st[++st[0]]=i; } while(st[0])r[st[st[0]--]]=n+1; for(int i=n;i;i--){ while(st[0]&&a[st[st[0]]]<a[i])l[st[st[0]--]]=i; st[++st[0]]=i; } while(st[0])l[st[st[0]--]]=0; for(int i=1;i<=m;++i){int l,r; scanf("%d%d",&l,&r);Ans[i]+=1ll*(r-l)*p1; eve1[++tot1]=event(l,r,r,i,1); eve1[++tot1]=event(l,r,l-1,i,-1); } sort(eve1+1,eve1+tot1+1,comp); for(int i=1;i<=n;++i){ if(l[i]&&r[i]!=n+1)eve2[++tot2]=event(l[i],l[i],r[i],0,p1); if(l[i]&&r[i]>i+1)eve2[++tot2]=event(i+1,r[i]-1,l[i],0,p2); if(r[i]!=n+1&&l[i]+1<i)eve2[++tot2]=event(l[i]+1,i-1,r[i],0,p2); } sort(eve2+1,eve2+tot2+1,comp); int h1(1),h2(1); while(!eve1[h1].h)h1++; for(int i=1;i<=n&&h1<=tot1;++i){ while(h2<=tot2&&eve2[h2].h==i){ BIT::Insert(eve2[h2].l,eve2[h2].r,eve2[h2].val); h2++; } while(h1<=tot1&&eve1[h1].h==i){ Ans[eve1[h1].bel]+=eve1[h1].val*(BIT::sum(eve1[h1].l,eve1[h1].r)); h1++; } } for(int i=1;i<=m;++i)cout<<Ans[i]<<"\n"; return 0; }