[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 个询问。
输入输出样例
10 5 2 3 7 9 5 1 3 10 6 8 2 4 1 7 1 9 1 3 5 9 1 5
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 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 typedef long long lol; 8 struct ZYYS 9 { 10 int c,p,l,r; 11 }q[900005]; 12 int pos,ch[5000001][2],root[200005],a[200005],sta[200005],top,n,m,lst[200005],nxt[200005],cnt; 13 lol sum[5000001],lazy[5000001],p1,p2; 14 bool cmp(ZYYS a,ZYYS b) 15 { 16 return a.p<b.p; 17 } 18 void update(int &rt,int l,int r,int L,int R,lol k,int last) 19 { 20 int x=rt; 21 if (rt<=last) 22 { 23 rt=++pos; 24 ch[rt][0]=ch[x][0];ch[rt][1]=ch[x][1]; 25 sum[rt]=sum[x]; 26 lazy[rt]=lazy[x]; 27 } 28 if (l>=L&&r<=R) 29 { 30 sum[rt]+=(r-l+1)*k; 31 lazy[rt]+=k; 32 return ; 33 } 34 int mid=(l+r)/2; 35 if (L<=mid) update(ch[rt][0],l,mid,L,R,k,last); 36 if (R>mid) update(ch[rt][1],mid+1,r,L,R,k,last); 37 sum[rt]=sum[ch[rt][0]]+sum[ch[rt][1]]+(r-l+1)*lazy[rt]; 38 } 39 lol query(int x,int y,int l,int r,int L,int R,lol la) 40 { 41 if (l>=L&&r<=R) 42 { 43 return sum[y]-sum[x]+la*(r-l+1); 44 } 45 int mid=(l+r)/2; 46 lol s=0; 47 if (L<=mid) s+=query(ch[x][0],ch[y][0],l,mid,L,R,la+lazy[y]-lazy[x]); 48 if (R>mid) s+=query(ch[x][1],ch[y][1],mid+1,r,L,R,la+lazy[y]-lazy[x]); 49 return s; 50 } 51 int main() 52 {int i,x,l,r,last=0; 53 cin>>n>>m>>p1>>p2; 54 for (i=1;i<=n;i++) 55 scanf("%d",&a[i]); 56 top=0; 57 for (i=1;i<=n;i++) 58 { 59 while (top&&a[sta[top]]<a[i]) top--; 60 lst[i]=sta[top]; 61 top++; 62 sta[top]=i; 63 } 64 top=0; 65 sta[0]=n+1; 66 for (i=n;i>=1;i--) 67 { 68 while (top&&a[sta[top]]<a[i]) top--; 69 nxt[i]=sta[top]; 70 top++; 71 sta[top]=i; 72 } 73 for (i=1;i<=n;i++) 74 { 75 if (lst[i]&&nxt[i]<=n) 76 { 77 q[++cnt]=(ZYYS){1,lst[i],nxt[i],nxt[i]}; 78 q[++cnt]=(ZYYS){1,nxt[i],lst[i],lst[i]}; 79 } 80 if (lst[i]&&nxt[i]-i>1) 81 q[++cnt]=(ZYYS){2,lst[i],i+1,nxt[i]-1}; 82 if (nxt[i]<=n&&i-lst[i]>1) 83 q[++cnt]=(ZYYS){2,nxt[i],lst[i]+1,i-1}; 84 } 85 sort(q+1,q+cnt+1,cmp); 86 x=0; 87 last=0; 88 for (i=1;i<=cnt;i++) 89 { 90 while (x<q[i].p) root[x+1]=root[x],x++,last=pos; 91 if (q[i].c==1) 92 update(root[x],1,n,q[i].l,q[i].r,p1,last); 93 else update(root[x],1,n,q[i].l,q[i].r,2*p2,last); 94 } 95 while (x<n) root[x+1]=root[x],x++; 96 for (i=1;i<=m;i++) 97 { 98 scanf("%d%d",&l,&r); 99 printf("%lld\n",query(root[l-1],root[r],1,n,l,r,0)/2+(r-l)*p1); 100 } 101 }
1 #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