HNOI2017影魔

影魔
  • 这么简单的方法尽然想不到,我是真的菜
  • 对每个点,用单调栈的方式处理出他左右第一个比他大的数的位置,你可以把\(0\)和\(n+1\)设成\(inf\)。
  • 显然对于每对\(lef[i]\)和\(rig[i]\)都会做出\(p1\)的贡献
  • 每个\(lef[i]\)会对\(i+1\)到\(rig[i]-1\)做出\(p2\)贡献
  • 同理,每个\(rig[i]\)都会给\(lef[i]+1\)到\(i-1\)做出\(p2\)贡献
  • 用结构体存下来,按顺序用线段树将贡献加入即可
  • 统计贡献,对于每个询问\(l-r\)在扫到\(l-1\)时将这段区间减去,在扫到\(r\)时再将这段区间贡献加上即可
    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=2e5+5;
    bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
    bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
    template<typename T>inline T read()
    {
    T f=1,ans=0;
    char ch=getchar();
    while(!isdigit(ch)&&ch!=‘-‘)ch=getchar();
    if(ch==‘-‘)f=-1,ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-‘0‘),ch=getchar();
    return ans*f;
    }
    template<typename T>inline void write(T x,char y)
    {
    if(x==0)
    {
        putchar(‘0‘);putchar(y);
        return;
    }
    if(x<0)
    {
        putchar(‘-‘);
        x=-x;
    }
    static char wr[20];
    int top=0;
    for(;x;x/=10)wr[++top]=x%10+‘0‘;
    while(top)putchar(wr[top--]);
    putchar(y);
    }
    void file()
    {
    #ifndef ONLINE_JUDGE
        freopen("3722.in","r",stdin);
        freopen("3722.out","w",stdout);
    #endif
    }
    int n,m,p1,p2;
    int a[N];
    struct Q
    {
    int l,r,x,tag,id;
    bool operator < (const Q &s)const {return x<s.x;}
    }opt[N<<2];
    int cnt;
    ll ans[N];
    void input()
    {
    int l,r;
    n=read<int>();m=read<int>();p1=read<int>();p2=read<int>();
    For(i,1,n)a[i]=read<int>();
    For(i,1,m)
    {
        l=read<int>();r=read<int>();
        ans[i]+=1ll*(r-l)*1ll*p1;
        opt[++cnt]=(Q){l,r,l-1,-1,i};
        opt[++cnt]=(Q){l,r,r,1,i};
    }
    }
    const int inf=0x3f3f3f3f;
    namespace Tree
    {
    #define mid ((l+r)>>1)
    #define lson h<<1,l,mid
    #define rson h<<1|1,mid+1,r
    ll sum[N<<2],lazy[N<<2];
    void push_up(int h)
    {
        sum[h]=sum[h<<1]+sum[h<<1|1];
    }
    void push_down(int h,int l,int r)
    {
        if(!lazy[h])return;
        int ls=h<<1,rs=ls|1;
        lazy[ls]+=lazy[h];lazy[rs]+=lazy[h];
        sum[ls]+=lazy[h]*1ll*(mid-l+1);
        sum[rs]+=lazy[h]*1ll*(r-mid);
        lazy[h]=0;
    }
    void update(int h,int l,int r,int s,int t,ll v)
    {
        if(s<=l&&r<=t)
        {
            lazy[h]+=v;
            sum[h]+=1ll*v*1ll*(r-l+1);
        }
        else
        {
            push_down(h,l,r);
            if(s<=mid)update(lson,s,t,v);
            if(mid<t)update(rson,s,t,v);
            push_up(h);
        }
    }
    ll query(int h,int l,int r,int s,int t)
    {
        if(s<=l&&r<=t)return sum[h];
        push_down(h,l,r);
        ll res=0;
        if(s<=mid)res=query(lson,s,t);
        if(mid<t)res+=query(rson,s,t);
        push_up(h);
        return res;
    }
    }
    #define rg register
    int lef[N],rig[N];
    struct node
    {
    int l,r,x;
    ll v;
    bool operator < (const node &s)const {return x<s.x;}
    }e[N<<2];
    int sz;
    void init()
    {
    int j;
    sort(opt+1,opt+cnt+1);
    a[0]=a[n+1]=inf;
    For(i,1,n)
    {
        for(j=i-1;j>=0;j=lef[j])if(a[j]>a[i])break;
        lef[i]=j;
    }
    Fordown(i,n,1)
    {
        for(j=i+1;j<=n+1;j=rig[j])if(a[j]>a[i])break;
        rig[i]=j;
    }
    //For(i,1,n)cout<<lef[i]<<‘ ‘<<rig[i]<<endl;
    For(i,1,n)
    {
        if(lef[i]+1<i&&rig[i]<=n)e[++sz]=(node){lef[i]+1,i-1,rig[i],p2};
        if(1<=lef[i]&&rig[i]>i+1)e[++sz]=(node){i+1,rig[i]-1,lef[i],p2};
        if(1<=lef[i]&&rig[i]<=n)e[++sz]=(node){lef[i],lef[i],rig[i],p1};
    }
    sort(e+1,e+sz+1);
    }
    void work()
    {
    int pos1=1,pos2=1;
    while(pos2<=cnt&&!opt[pos2].x)pos2++;
    //cerr<<pos2<<‘ ‘<<cnt<<endl;
    For(i,1,n)
    {
        for(;pos1<=sz&&e[pos1].x==i;++pos1)
            Tree::update(1,0,n,e[pos1].l,e[pos1].r,e[pos1].v);
        for(;pos2<=cnt&&opt[pos2].x==i;++pos2)
            ans[opt[pos2].id]+=Tree::query(1,0,n,opt[pos2].l,opt[pos2].r)*opt[pos2].tag;
    }
    For(i,1,m)write(ans[i],‘\n‘);
    }
    int main()
    {
    file();
    input();
    init();
    work();
    return 0;
    }

原文地址:https://www.cnblogs.com/dengyixuan/p/8361947.html

时间: 2024-10-09 03:10:23

HNOI2017影魔的相关文章

[BZOJ4826][HNOI2017]影魔(主席树)

4826: [Hnoi2017]影魔 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 669  Solved: 384[Submit][Status][Discuss] Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己的战斗力,而影魔,靠 这些战斗力提升自己的攻击.奈文摩尔有 n 个

[HNOI2017]影魔

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

Bzoj4826 [Hnoi2017]影魔

Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 425  Solved: 244 Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己的战斗力,而影魔,靠 这些战斗力提升自己的攻击.奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n. 第 i个灵魂的战斗力

AC日记——[Hnoi2017]影魔 bzoj 4826

4826 思路: 主席树矩阵加减+单调栈预处理: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define ll long long #define maxtree maxn*30 class PTreeType { private: int ch[maxtree][2],root[maxn],tot,head[maxn],li[maxn<<1],ri[maxn<<1],E

BZOJ4826 [Hnoi2017]影魔 【线段树 + 单调栈】

题目链接 BZOJ4826 题解 蒟蒻智力水平捉急orz 我们会发现相邻的\(i\)和\(j\)贡献一定是\(p1\),可以很快算出来[然而我一开始忘了考虑调了半天] 我们现在只考虑不相邻的 我们只需要找出所有产生贡献的\(i,j\)即可 我们发现每一个产生贡献的\(i,j\)都能对应到一个三元组\((i,k,j)\),分别对应区间的最大值,次大值,第三大值 我们枚举中间位置\(i\),找到\(i\)左边第一个比\(i\)大的位置\(L[i]\),右边第一个比\(i\)大的位置\(R[i]\)

Hnoi2017试题泛做

Day1 4825: [Hnoi2017]单旋 注意到二叉查找树的一个性质:其中序遍历就是所有元素按权值排序的顺序. 所以我们可以离线地把这棵树的中序遍历求出来.然后我们在插入的时候就可以用一个set来维护前驱后继,这样就可以维护出整棵树的形态. 接着我们发现将最大.最小单旋到根后,一定会有一边儿子是空的,并且剩下的子树的深度+1.于是我们就只要支持单点修改.区间加.单点查询的数据结构即可.树状数组就好了. 然后树的形态维护的时候大力判断一下就好啦. 1 #include <cstdio> 2

HNOI2017 day1 T2 影魔

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

BZOJ 4826 【HNOI2017】 影魔

题目链接:影魔 这道题就是去年序列的弱化版啊-- 我们枚举最大值的位置\(i\),找出左边第一个比\(a_i\)大的位置\(l\),右边第一个比\(a_i\)大的位置\(r\),然后我们分开考虑一下\(p_1\)和\(p_2\)的贡献. 首先由于\(a_i\)为最大值,那么左端点不会小于\(l\),右端点不会大于\(r\). 容易发现只有左端点为\(l\),右端点为\(r\)才会产生\(p_1\)的贡献. 然后产生\(p_2\)贡献的有两种:一种是左端点为\(l\),右端点在区间\((i,r)\

HNOI2017游记

HNOI 2017 游记 DAY 0 省选即将来临,上午写了一道noip2015运输计划,复习了下LCA,中午与QYP写数列操作,他用分块写,我用线段树写,我码了七十多行代码,他有四十多行代码,我比他先打完,哈哈哈. 下午有点浪费时间,不知道干甚么,之后与高二学长们一起在楼顶开了一个振奋人心的会,我们教练与高二竞赛一班班主任做了精彩的演讲,还有学长们的经验分享.然后晚自习练习了.emcas文件配置,与欧拉函数,线性筛,希望明天万一考到打个暴力也好.就这样,回去早早睡了(也到了11点). Day