题目传送门
题目背景
影魔,奈文摩尔,据说有着一个诗人的灵魂。 事实上,他吞噬的诗人灵魂早已成千上万。
千百年来,他收集了各式各样的灵魂,包括诗人、 牧师、 帝王、 乞丐、 奴隶、 罪人,当然,还有英雄。
题目描述
每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。
奈文摩尔有 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 个询问。
输入输出样例
说明
30%: 1<= n,m <= 500。
另 30%: p1=2*p2。
100%:1 <= n,m <= 200000; 1 <= p1,p2 <= 1000。
30分明显暴力。
60分不懂。。。
一开始觉得是预处理了之后询问O(1),仔细想了想之后根本不可能啊...空间开不下。
然后就不会了。。。
正解是扫描线+线段树。
我们不去考虑点对,我们考虑每一个数对答案的贡献,即每个数是多少点对之间的最大值。我们只要找到左边第一个比它大的数l[x],右边第一个比它大的数r[x]。那么对于点对(l[x],r[x])来说,他有贡献p1,对于(l[x],i)(x<i<r[x])、(i,r[x])(l[x]<i<x) 来说他有贡献p2。
我们可以把询问和原数据抽象成二维平面中的一条条线段,扫描线从左往右扫一遍即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define LL long long 6 #define RI register int 7 using namespace std; 8 const int INF = 0x7ffffff ; 9 const int N = 200000 + 10 ; 10 11 inline int read() { 12 int k = 0 , f = 1 ; char c = getchar() ; 13 for( ; !isdigit(c) ; c = getchar()) 14 if(c == '-') f = -1 ; 15 for( ; isdigit(c) ; c = getchar()) 16 k = k*10 + c-'0' ; 17 return k*f ; 18 } 19 struct node { 20 int l, r, x, bl ; LL z ; 21 }s1[N<<1], s2[N*3] ; 22 int n, m, p1, p2 ; int k[N], l1[N], r1[N] ; LL ans[N] ; 23 24 inline void init() { 25 int head = 0 ; int hh[N] ; 26 for(int i=1;i<=n;i++) { 27 while(head && k[hh[head]] < k[i]) head-- ; 28 if(head) l1[i] = hh[head] ; else l1[i] = 0 ; 29 hh[++head] = i ; 30 } 31 head = 0 ; 32 for(int i=n;i;i--) { 33 while(head && k[hh[head]] < k[i]) head-- ; 34 if(head) r1[i] = hh[head] ; else r1[i] = n+1 ; 35 hh[++head] = i ; 36 } 37 } 38 39 struct Node { 40 LL sum, laz ; 41 Node *ls, *rs ; 42 inline void pushup() { 43 sum = ls->sum + rs->sum ; 44 } 45 inline void pushdown(int l,int r) { 46 if(!laz) return ; int mid = (l+r)>>1 ; 47 ls->sum += laz*(mid-l+1) ; rs->sum += laz*(r-mid) ; 48 ls->laz += laz, rs->laz += laz ; 49 laz = 0 ; 50 } 51 }pool[N<<1] ; LL res = 0 ; 52 inline Node *newNode() { 53 static int cnt = 0 ; 54 return &pool[++cnt] ; 55 } 56 Node *build(int l,int r) { 57 Node *cur = newNode() ; 58 if(l == r) { 59 cur->laz = cur->sum = 0 ; 60 } else { 61 int mid = (l+r)>>1 ; 62 cur->ls = build(l,mid) ; cur->rs = build(mid+1,r) ; 63 cur->pushup() ; 64 } 65 return cur ; 66 } 67 void change_interval(Node *cur,int l,int r,int a,int b,LL x) { 68 if(l >= a && r <= b) { 69 cur->sum += x*(r-l+1) ; cur->laz += x ; return ; 70 } 71 int mid = (l+r)>>1 ; cur->pushdown(l,r) ; 72 if(a <= mid) change_interval(cur->ls,l,mid,a,b,x) ; 73 if(b > mid) change_interval(cur->rs,mid+1,r,a,b,x) ; 74 cur->pushup() ; 75 } 76 void ask_interval(Node *cur,int l,int r,int a,int b) { 77 if(l >= a && r <= b) { 78 res += cur->sum ; return ; 79 } 80 int mid = (l+r)>>1 ; cur->pushdown(l,r) ; 81 if(a <= mid) ask_interval(cur->ls,l,mid,a,b) ; 82 if(b > mid) ask_interval(cur->rs,mid+1,r,a,b) ; 83 } 84 85 inline bool cmp1(node s,node t) { return s.x < t.x ; } 86 int main() { 87 n = read(), m = read(), p1 = read(), p2 = read() ; 88 for(int i=1;i<=n;i++) k[i] = read() ; 89 init() ; 90 for(int i=1;i<=m;i++) { 91 int ll = read(), rr = read() ; ans[i] += (rr-ll)*p1 ; 92 s1[i] = (node){ll,rr,rr,i,1} ; 93 s1[i+m] = (node){ll,rr,ll-1,i,-1} ; 94 } 95 int tt = 0 ; 96 for(int i=1;i<=n;i++) { 97 if(l1[i] && r1[i] <= n) s2[++tt] = (node){l1[i],l1[i],r1[i],0,p1} ; 98 if(l1[i] && r1[i] > i+1) s2[++tt] = (node){i+1,r1[i]-1,l1[i],0,p2} ; 99 if(r1[i] <= n && l1[i] < i-1) s2[++tt] = (node){l1[i]+1,i-1,r1[i],0,p2} ; 100 } 101 sort(s1+1,s1+m*2+1,cmp1) ; sort(s2+1,s2+tt+1,cmp1) ; 102 int n1 = 1, n2 = 1 ; Node *root = build(1,n) ; 103 while(!s1[n1].x) n1 ++ ; 104 for(int i=1 ; i<=n && n1<=2*m ; i++) { 105 while(s2[n2].x == i && n2 <= tt) { 106 change_interval(root,1,n,s2[n2].l,s2[n2].r,s2[n2].z) ; n2++ ; 107 } 108 while(s1[n1].x == i && n1 <= m*2) { 109 res = 0 ; ask_interval(root,1,n,s1[n1].l,s1[n1].r) ; 110 ans[s1[n1].bl] += s1[n1].z*res ; n1++ ; 111 // printf("%d %d %d %d\n",s1[n1].bl,s1[n1].z,s1[n1].x,res) ; 112 } 113 } 114 115 // for(int i=1;i<=m*2;i++) printf("%d\n",s1[i].x) ; 116 // for(int i=1;i<=n;i++) printf("%d : %d %d\n",i,l1[i],r1[i]) ; 117 118 for(int i=1;i<=m;i++) printf("%lld\n",ans[i]) ; 119 return 0 ; 120 }