• [HNOI2017/AHOI2017]影魔


    Description:

    奈文摩尔有 (n) 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 (1)(n)。第 (i) 个灵魂的战斗力为 (k_i),灵魂们以点对的形式为影魔提供攻击力。对于灵魂对 (i, j) 来说,若不存在 $k_s $ 大于 (k_i) 或者 (k_j),则会为影魔提供 (p_1) 的攻击力。另一种情况,令 (c)(k_{i + 1}, k_{i + 2}, cdots, k_{j -1}) 的最大值,若 (c) 满足:(k_i ; c > k_j),或者 (k_j lt; c lt; k_i),则会为影魔提供 (p_2) 的攻击力,当这样的 (c) 不存在时,自然不会提供这 (p_2) 的攻击力;其他情况的点对,均不会为影魔提供攻击力。
    影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间 ([a, b]),位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑所有满足 (ale ilt;jle b) 的灵魂对 (i, j) 提供的攻击力之和。
    顺带一提,灵魂的战斗力组成一个 (1)(n) 的排列:(k_1, k_1, cdots, k_n)

    Hint:

    对于 (30\%) 的数据,(1le n, mle 500)
    另有 (30\%) 的数据,(p_1 = 2p_2)
    对于 (100\%) 的数据,(1le n,mle 200000, 1le p_1, p_2le 1000)

    Solution:

    这题直接统计不好统计

    我们反过来考虑每个位置对区间的贡献

    首先预处理出每个位置左右第一个大于它的位置

    1.(i​)对于区间((l[i] ,r[i]​)),有(p_1​)的贡献,我们在扫到(r[i]​)更新(l[i]​)即可

    2.(i)对于所有区间((l[i],i+1 ext{~} r[i]-1))(p_2)的贡献,我们在扫到(l[i])时更新(i+1 ext{~} r[i]-1)

    3.(i​)对于所有区间((l[i]+1 ext{~}i-1,r[i])​)(p_2​)的贡献,我们在扫到(r[i]​)时更新(l[i]+1 ext{~}i-1​)

    然后把询问离线拆成(l,r)后按端点排序,每次询问区间(l~r)的和,答案就是两次询问相减

    注意要特判相邻位置的贡献

    update:
    今天体育课ysbs给我讲了一个更优秀的方法,实际上没必要处理出每个点的左右边界
    对于贡献2,我们只要枚举所有以该点为右端点的区间,单调栈维护最近的大于该点的位置
    分为左大于右和左小于右两种情况分别做一次就行,这样稍微方便一些

    #include <map>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ls p<<1 
    #define rs p<<1|1
    using namespace std;
    typedef long long ll;
    const ll mxn=1e6+5;
    ll n,m,p1,p2,tot,cnt1,cnt2,a[mxn],lt[mxn],rt[mxn],ans[mxn];
    ll hd1[mxn],hd2[mxn],tr[mxn<<2],tag[mxn<<2];
    
    struct Q {
        ll pos,l,r,id;	
    }q[mxn];
    
    struct ed {
        ll to1,to2,nxt;
    }t1[mxn],t2[mxn];
    
    inline ll read() {
        char c=getchar(); ll x=0,f=1;
        while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
        while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
        return x*f;
    }
    inline ll chkmax(ll &x,ll y) {if(x<y) x=y;}
    inline ll chkmin(ll &x,ll y) {if(x>y) x=y;}
    
    ll cmp(Q x,Q y) {
        return x.pos<y.pos;
    }
    
    inline void add1(ll u,ll v) {
        t1[++cnt1]=(ed) {v,0,hd1[u]};
        hd1[u]=cnt1;
    }
    
    inline void add2(ll u,ll v,ll w) {
        t2[++cnt2]=(ed) {v,w,hd2[u]};
        hd2[u]=cnt2;
    }
    
    void push_up(ll p) {
        tr[p]=tr[ls]+tr[rs];
    }
    
    void push_down(ll l,ll r,ll p) {
        if(tag[p]) {
            ll mid=(l+r)>>1;
            tr[ls]+=(mid-l+1)*tag[p];
            tr[rs]+=(r-mid)*tag[p];
            tag[ls]+=tag[p];
            tag[rs]+=tag[p];
            tag[p]=0;
        }
    }
    
    void update1(ll l,ll r,ll pos,ll val,ll p)
    {
        if(l==r) {
            tr[p]+=val;
            return ;
        }
        ll mid=(l+r)>>1; push_down(l,r,p);
        if(pos<=mid) update1(l,mid,pos,val,ls); 
        else update1(mid+1,r,pos,val,rs);
        push_up(p);
    }
    
    void update2(ll l,ll r,ll ql,ll qr,ll val,ll p)
    {
        if(ql<=l&&r<=qr) {
            tr[p]+=val*(r-l+1);
            tag[p]+=val;
            return ;
        }
        ll mid=(l+r)>>1; push_down(l,r,p);
        if(ql<=mid) update2(l,mid,ql,qr,val,ls);
        if(qr>mid) update2(mid+1,r,ql,qr,val,rs);
        push_up(p);
    }
    
    ll query(ll l,ll r,ll ql,ll qr,ll p)
    {
        if(ql<=l&&r<=qr) return tr[p];
        ll mid=(l+r)>>1; push_down(l,r,p); ll res=0;
        if(ql<=mid) res+=query(l,mid,ql,qr,ls);
        if(qr>mid) res+=query(mid+1,r,ql,qr,rs);
        return res;
    }
    
    int main()
    {
        n=read(); m=read(); p1=read(); p2=read(); ll l,r;
        for(ll i=1;i<=n;++i) a[i]=read();
        for(ll i=1;i<=m;++i) {
            l=read(),r=read();
            q[i]=(Q){l-1,l,r,i};
            q[i+m]=(Q){r,l,r,i+m};
        }
        stack<ll > st;
        for(ll i=1;i<=n;++i) {
            while(!st.empty()&&a[st.top()]<a[i]) st.pop(); 
            if(st.empty()) lt[i]=0;
            else lt[i]=st.top(); st.push(i);
        }
        while(!st.empty()) st.pop();
        for(ll i=n;i>=1;--i) {
            while(!st.empty()&&a[st.top()]<a[i]) st.pop();
            if(st.empty()) rt[i]=n+1;
            else rt[i]=st.top(); st.push(i);
            if(lt[i]+1!=rt[i]) add1(rt[i],lt[i]); 
            add2(rt[i],lt[i]+1,i-1); add2(lt[i],i+1,rt[i]-1); 
        }
        sort(q+1,q+2*m+1,cmp); ll pos=0;
        for(ll i=1;i<=2*m;++i) {
            while(pos<q[i].pos) {
                ++pos; if(pos-1!=0) update1(1,n,pos-1,p1,1);
                for(ll j=hd1[pos];j;j=t1[j].nxt) {
                    ll v=t1[j].to1;
                    if(v!=0) update1(1,n,v,p1,1);
                }
                for(ll j=hd2[pos];j;j=t2[j].nxt) {
                    ll v=t2[j].to1,w=t2[j].to2;
                    if(v!=0&&w!=0&&w!=n+1&&v!=n+1) update2(1,n,v,w,p2,1);
                }
            } 
            l=q[i].l; r=q[i].r;
            ans[q[i].id]=query(1,n,l,r,1);
        }
        for(ll i=1;i<=m;++i) printf("%lld
    ",ans[i+m]-ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    ok~加油!
    解析window.open链接的参数
    Arrya数组添加过滤条件
    Oracle 查询今天、昨日、本周、本月和本季度的所有记录
    Sql Server日期查询-SQL查询今天、昨天、7天内、30天
    Lua 中 pairs 和 ipairs 的区别
    关于SignalR连接数量问题的记录
    IceStorm示例运行步骤
    从 OPC 到 OPC UA
    SQL Server 2008 R2 Express Profiler
  • 原文地址:https://www.cnblogs.com/list1/p/10520711.html
Copyright © 2020-2023  润新知