影魔[AH2017/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。

  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
",s1[n1].bl,s1[n1].z,s1[n1].x,res) ;            
112         }
113     }
114     
115 //    for(int i=1;i<=m*2;i++) printf("%d
",s1[i].x) ;
116 //    for(int i=1;i<=n;i++) printf("%d : %d %d
",i,l1[i],r1[i]) ;
117      
118     for(int i=1;i<=m;i++) printf("%lld
",ans[i]) ;
119     return 0 ;
120 }
原文地址:https://www.cnblogs.com/zub23333/p/8794021.html