[AH/HNOI2017]影魔
題目背景
影魔,奈文摩爾,據說有著一個詩人的靈魂。 事實上,他吞噬的詩人靈魂早已成千上萬。
千百年來,他收集了各式各樣的靈魂,包括詩人、 牧師、 帝王、 乞丐、 奴隸、 罪人,當然,還有英雄。
題目描述
每一個靈魂,都有著自己的戰鬥力,而影魔,靠這些戰鬥力提升自己的攻擊。
奈文摩爾有 n 個靈魂,他們在影魔寬廣的體內可以排成一排,從左至右標號 1 到 n。第 i個靈魂的戰鬥力為 k[i],靈魂們以點對的形式為影魔提供攻擊力,對於靈魂對 i, j(i<j)來說,若不存在 ks大 於 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]。
輸入輸出格式
輸入格式:輸入文件名為 sf.in。
第一行 n,m,p1,p2
第二行 n 個數: k[1],k[2],…,k[n]
接下來 m 行, 每行兩個數 a,b, 表示詢問區間[a,b]中的靈魂對會為影魔提供多少攻擊力。
輸出格式:輸出文件名為 sf.out
共輸出 m 行,每行一個答案,依次對應 m 個詢問。
輸入輸出樣例
輸入樣例#1:10 5 2 3 7 9 5 1 3 10 6 8 2 4 1 7 1 9 1 3 5 9 1 5輸出樣例#1:
30 39 4 13 16
說明
30%: 1<= n,m <= 500。
另 30%: p1=2*p2。
100%:1 <= n,m <= 200000; 1 <= p1,p2 <= 1000。
令L[i]為i前第一個比a[i]大的一位,R[i]為i後第一個比a[i]大的一位
1.每組(i,L[i]) (R[i],i) (i,i+1)可以貢獻p1 2.(L[i],j) (i+1<=j<=R[i]-1) (j,R[i])(L[i]+1<=j<=i-1) 都可以貢獻p21 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Ask 7 { 8 int l,r,id; 9 }q[200001]; 10 int a[200001],aa[200001],n,m,stack[200001],R[200001]; 11 long long c[800001],mark[800001],ans[200001],p1,p2; 12 bool cmp(Ask a,Ask b) 13 { 14 return a.l<b.l; 15 } 16 void pushup(int rt) 17 { 18 c[rt]=c[rt*2]+c[rt*2+1]; 19 } 20 void pushdown(int rt,int l,int r,int mid) 21 { 22 if (mark[rt]) 23 { 24 mark[rt*2]+=mark[rt]; 25 mark[rt*2+1]+=mark[rt]; 26 c[rt*2]+=mark[rt]*(mid-l+1); 27 c[rt*2+1]+=mark[rt]*(r-mid); 28 mark[rt]=0; 29 } 30 } 31 void change(int rt,int l,int r,int L,int R,long long d) 32 { 33 if (l>=L&&r<=R) 34 { 35 mark[rt]+=d; 36 c[rt]+=(r-l+1)*d; 37 return; 38 } 39 pushdown(rt,l,r,(l+r)/2); 40 int mid=(l+r)/2; 41 if (L<=mid) change(rt*2,l,mid,L,R,d); 42 if (R>mid) change(rt*2+1,mid+1,r,L,R,d); 43 pushup(rt); 44 } 45 long long getsum(int rt,int l,int r,int L,int R) 46 { 47 if (l>=L&&r<=R) 48 { 49 return c[rt]; 50 } 51 int mid=(l+r)/2; 52 pushdown(rt,l,r,mid); 53 long long s=0; 54 if (L<=mid) s+=getsum(rt*2,l,mid,L,R); 55 if (R>mid) s+=getsum(rt*2+1,mid+1,r,L,R); 56 pushup(rt); 57 return s; 58 } 59 void work() 60 {int i; 61 memset(c,0,sizeof(c)); 62 memset(mark,0,sizeof(mark)); 63 sort(q+1,q+m+1,cmp); 64 int top=0; 65 stack[0]=n+1; 66 for (i=n;i>=1;i--) 67 { 68 while (top&&a[i]>=a[stack[top]]) top--; 69 R[i]=stack[top]; 70 stack[++top]=i; 71 } 72 top=m; 73 for (i=n;i>=1;i--) 74 { 75 if (i+1<=R[i]-1) 76 change(1,1,n,i+1,R[i]-1,p2); 77 change(1,1,n,R[i],R[i],p1-p2); 78 while (top&&q[top].l==i) 79 ans[q[top].id]+=getsum(1,1,n,1,q[top].r),top--; 80 } 81 } 82 void rev() 83 {int i; 84 for (i=1;i<=n;i++) 85 aa[i]=a[n-i+1]; 86 for (i=1;i<=n;i++) 87 a[i]=aa[i]; 88 } 89 int main() 90 {int i; 91 cin>>n>>m>>p1>>p2; 92 for (i=1;i<=n;i++) 93 { 94 scanf("%d",&a[i]); 95 } 96 for (i=1;i<=m;i++) 97 { 98 scanf("%d%d",&q[i].l,&q[i].r); 99 q[i].id=i; 100 } 101 work(); 102 rev(); 103 for (i=1;i<=m;i++) 104 q[i].l=n+1-q[i].l,q[i].r=n+1-q[i].r,swap(q[i].l,q[i].r); 105 work(); 106 for (i=1;i<=m;i++) 107 printf("%lld\n",ans[i]); 108 }
慶祝FGO第一/二個SSR
[AH/HNOI2017]影魔