• 影魔[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 }
  • 相关阅读:
    [转][LeetCode]Longest Common Prefix ——求字符串的最长公共前缀
    [转]最长回文子串——4种解法
    [转]通过金矿模型介绍动态规划
    一句话说清楚什么是闭包函数
    [转]as3事件流机制彻底理解
    Eclipse 快捷键
    文件打包与解压缩
    第5节 环境变量与文件查找
    vim的多标签
    java思维导图
  • 原文地址:https://www.cnblogs.com/zub23333/p/8794021.html
Copyright © 2020-2023  润新知