zoukankan      html  css  js  c++  java
  • bzoj 4826: [Hnoi2017]影魔

    Description

    影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样
    的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠
    这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。
    第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i<j)来说,若不存在 k[s](i
    <s<j)大于 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 的排列:k1,k[2],...,k[n]。

    solution

    这题很久以前写过线段树做法,见这里
    但线段树做法感觉已经超越人类智慧,不指望考场能够想得出,考虑主席树做法.
    我在上一篇博客说过一句打酱油的话,但是这题主席树做法的关键:
    当考虑一个位置 (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)
    考虑处理询问,我们以左端点为下标,右段点为值域开主席树
    注意一下标记可持久化

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    typedef long long ll;
    const int N=200041,M=12000005;
    int n,m,a[N],st[N],L[N],R[N],tot=0;ll p1,p2;
    struct node{
      int x,l,r,op;
      node(){}
      node(int _x,int _l,int _r,int _op){x=_x;l=_l;r=_r;op=_op;}
      bool operator <(const node &pr)const{return x<pr.x;}
    }q[N<<2];
    void priwork(){
      int top=0;
      for(int i=1;i<=n;i++){
        while(top && a[i]>a[st[top]])R[st[top]]=i,top--;
        L[i]=st[top];st[++top]=i;
      }
      while(top)R[st[top--]]=n+1;
    }
    struct Tree{
      int ls,rs,mark;ll val;
    }tr[M];
    int root[N],totnode=0;
    inline void upd(int &x,int y,int l,int r,int sa,int se,ll t){
      x=++totnode;tr[x]=tr[y];
      if(l==sa && r==se){tr[x].val+=(r-l+1)*t;tr[x].mark+=t;return ;}
      int mid=(l+r)>>1;
      if(se<=mid)upd(tr[x].ls,tr[y].ls,l,mid,sa,se,t);
      else if(sa>mid)upd(tr[x].rs,tr[y].rs,mid+1,r,sa,se,t);
      else {
        upd(tr[x].ls,tr[y].ls,l,mid,sa,mid,t);
        upd(tr[x].rs,tr[y].rs,mid+1,r,mid+1,se,t);
      }
      tr[x].val=tr[tr[x].ls].val+tr[tr[x].rs].val+tr[x].mark*(r-l+1);
    }
    inline ll qry(int x,int y,int l,int r,int sa,int se,ll mr){
      if(l==sa && r==se)return tr[y].val-tr[x].val+(r-l+1)*mr;
      int mid=(l+r)>>1;
      ll ret=0;mr+=tr[y].mark-tr[x].mark;
      if(se<=mid)ret=qry(tr[x].ls,tr[y].ls,l,mid,sa,se,mr);
      else if(sa>mid)ret=qry(tr[x].rs,tr[y].rs,mid+1,r,sa,se,mr);
      else {
        ret+=qry(tr[x].ls,tr[y].ls,l,mid,sa,mid,mr);
        ret+=qry(tr[x].rs,tr[y].rs,mid+1,r,mid+1,se,mr);
      }
      return ret;
    }
    void work()
    {
      scanf("%d%d%lld%lld",&n,&m,&p1,&p2);
      for(int i=1;i<=n;i++)scanf("%d",&a[i]);
      priwork();
      for(int i=1;i<=n;i++){
        if(L[i] && R[i]<=n)q[++tot]=node(L[i],R[i],R[i],1);
        if(R[i]<=n && L[i]+1<=i-1)q[++tot]=node(R[i],L[i]+1,i-1,2);
        if(L[i]>=1 && i+1<=R[i]-1)q[++tot]=node(L[i],i+1,R[i]-1,2);
      }
      int x=0,y;
      sort(q+1,q+tot+1);
      for(int i=1;i<=tot;i++){
        while(x<q[i].x)x++,root[x]=root[x-1];
        upd(root[x],root[x],1,n,q[i].l,q[i].r,(q[i].op==1?p1:p2));
      }
      for(int i=x;i<n;i++)root[i+1]=root[i];
      while(m--){
        scanf("%d%d",&x,&y);
        printf("%lld
    ",qry(root[x-1],root[y],1,n,x,y,0)+(y-x)*p1);
      }
    }
    
    int main()
    {
      work();
      return 0;
    }
    
    
  • 相关阅读:
    Ubuntu执行命令时,不sudo提示权限不足,sudo提示找不到该命令
    ubuntu中执行可执行文件时报错“没有那个文件或目录”的解决办法(非权限问题)
    不同编译器下,定义一个地址按x字节对齐的数组
    对冒泡排序法的个人理解
    通过py2exe打包python程序的过程中,解决的一系列问题
    IAR工程名修改
    stm8编程tips(stvd)
    获取单片机唯一id(stm32获取单片机唯一id)
    按键抖动的处理方法(按键外部中断)
    stm32--USB(作为U盘)+FatFs的实现
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7955373.html
Copyright © 2011-2022 走看看