1. 程式人生 > >[AH/HNOI2017]影魔

[AH/HNOI2017]影魔

clu 題目 情況 組成 自己 英雄 push 輸出 align

題目背景

影魔,奈文摩爾,據說有著一個詩人的靈魂。 事實上,他吞噬的詩人靈魂早已成千上萬。

千百年來,他收集了各式各樣的靈魂,包括詩人、 牧師、 帝王、 乞丐、 奴隸、 罪人,當然,還有英雄。

題目描述

每一個靈魂,都有著自己的戰鬥力,而影魔,靠這些戰鬥力提升自己的攻擊。

奈文摩爾有 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) 都可以貢獻p2
然後就是統計: 我們假設i和[i+1,R[i]-1]之間的數都可以搭配成p2的條件,然後我們就在線段樹中把[i+1,R[i]-1]加上p2. 因為(i,R[i])在反方向算作了p2,所以應該+p1-p2,這樣反向算時等價於只+p1 對於i和L[i],把數列和詢問反轉,在做一次相同操作 %%%%%YZH巨佬http://www.cnblogs.com/Yuzao/p/6930974.html
  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

[AH/HNOI2017]影魔