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 的排列:k[1],k[2],...,k[n]。

    Input

    第一行 n,m,p1,p2
    第二行 n 个数:k[1],k[2],...,k[n]
    接下来 m 行,每行两个数 a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
    1 <= n,m <= 200000;1 <= p1,p2 <= 1000

    Output

    共输出 m 行,每行一个答案,依次对应 m 个询问。
     
    对于点 $i$,用单调栈求出左边和右边第一个大于 $i$ 的位置,记为 $l[i]$ 与 $r[i]$.    
    那么 $(l[i],r[i])$ 会产生 $p1$ 的贡献.  
    左端点为 $l[i]$,则如果右端点在 $[i+1,r-1]$ 的话都会产生 $p1$ 的贡献. 
    而右端点在 $r[i]$,左端点在 $[l+1,i-1]$ 都会产生 $p2$ 的贡献.   
    因为这个东西有一个端点是固定的,另一个区间是连续区间,所以可以用主席树来维护.  
    由于 $pushdown$ 函数比较麻烦,这里用的标记永久化.   
    #include <cstring> 
    #include <cstdio> 
    #include <stack>  
    #include <string> 
    #include <vector>  
    #include <algorithm>  
    #define N 200005 
    #define ll long long      
    using namespace std;   
    void setIO(string s) {
        string in=s+".in"; 
        string out=s+".out"; 
        freopen(in.c_str(),"r",stdin);   
        // freopen(out.c_str(),"w",stdout);   
    }              
    int n,m,tp,edges;    
    int p1,p2;    
    int val[N];         
    int sta[N]; 
    int L[N],R[N];                
    int hd[N];   
    int tot;   
    int rtl[N]; 
    int rtr[N];   
    struct Edge {          
        int x; 
        int l; 
        int r;  
        int v;   
        int nex; 
    }e[N*3];   
    struct node {
        int ls; 
        int rs;  
        ll tag;  
        ll sum;  
    }t[N*80];   
    void add(int u,int l,int r,int v) {
        e[++edges].nex=hd[u];  
        hd[u]=edges;   
        e[edges].l=l; 
        e[edges].r=r;  
        e[edges].x=u; 
        e[edges].v=v;  
    }
    int newnode() {
        return ++tot; 
    }      
    int update(int x,int l,int r,int L,int R,int v) {   
        if(L>R) {
            return x;   
        }
        int now=newnode();              
        t[now]=t[x];                                                      
        t[now].sum+=(ll)(min(r,R)-max(l,L)+1)*v; 
        if(l>=L&&r<=R) {            
            t[now].tag+=v;                
            return now;  
        }
        int mid=(l+r)>>1;   
        if(L<=mid) {
            t[now].ls=update(t[x].ls,l,mid,L,R,v); 
        }
        if(R>mid)  {
            t[now].rs=update(t[x].rs,mid+1,r,L,R,v);   
        }    
        return now;        
    }
    ll query(int x,int l,int r,int L,int R) {           
        if(!x) {
            return 0;  
        }
        if(l>=L&&r<=R) {
            return t[x].sum; 
        }
        int mid=(l+r)>>1;    
        ll re=(ll)t[x].tag*(min(r,R)-max(l,L)+1);                                     
        if(L<=mid)  {
            re+=query(t[x].ls,l,mid,L,R); 
        }
        if(R>mid) {
            re+=query(t[x].rs,mid+1,r,L,R); 
        }
        return re;  
    }       
    int main() { 
        // setIO("input");   
        int i,j;                 
        scanf("%d%d%d%d",&n,&m,&p1,&p2);    
        for(i=1;i<=n;++i) {
            scanf("%d",&val[i]); 
        }             
        for(i=1;i<=n;++i) {
            while(tp&&val[sta[tp]]<val[i]) {
                --tp;   
            }
            L[i]=sta[tp];   
            sta[++tp]=i;  
        }      
        sta[tp=0]=n+1;   
        for(i=n;i>=1;--i) {
            while(tp&&val[sta[tp]]<val[i]) {
                --tp;  
            }
            R[i]=sta[tp];  
            sta[++tp]=i; 
        }              
        for(i=1;i<=n;++i) {    
            add(L[i],R[i],R[i],p1);                    
            add(L[i],i+1,R[i]-1,p2);   
            add(R[i],L[i]+1,i-1,p2);  
        }           
        // 向右   
        for(i=1;i<=n;++i) {
            rtl[i]=rtl[i-1];   
            for(j=hd[i];j;j=e[j].nex) {
                if(e[j].l>i) {  
                    rtl[i]=update(rtl[i],1,n,max(1,e[j].l),min(n,e[j].r),e[j].v);                
                }
            }
            if(i!=n) {  
                rtl[i]=update(rtl[i],1,n,i+1,i+1,p1);  
            }
        }
        for(i=n;i>=1;--i) {
            rtr[i]=rtr[i+1];   
            for(j=hd[i];j;j=e[j].nex) {
                if(e[j].r<i) {    
                    rtr[i]=update(rtr[i],1,n,max(1,e[j].l),min(n,e[j].r),e[j].v);   
                }
            }
        }        
        while(m--) {
            int x,y; 
            scanf("%d%d",&x,&y);    
            ll ans=0ll;   
            ans+=query(rtl[y],1,n,x,y); 
            ans-=query(rtl[x-1],1,n,x,y); 
            ans+=query(rtr[x],1,n,x,y); 
            ans-=query(rtr[y+1],1,n,x,y);    
            printf("%lld
    ",ans);   
        }    
        return 0; 
    }
    

      

  • 相关阅读:
    2.4 自给自足的脚本:位于第一行的#!
    2.3 一个简单的脚本
    2.2 为什么要使用Shell脚本
    JSON 字符串 与 java 对象的转换
    ajax异步提交文件
    jquery选择器
    发现前端框架 bui-min.js
    学习hsf
    Git详解
    java学习材料
  • 原文地址:https://www.cnblogs.com/guangheli/p/12061308.html
Copyright © 2011-2022 走看看