首页 > 其他分享 >P3722 [AH2017/HNOI2017] 影魔

P3722 [AH2017/HNOI2017] 影魔

时间:2023-11-05 20:13:46浏览次数:36  
标签:影魔 rs int top 数对 贡献 HNOI2017 区间 AH2017

题目链接

Part1

先想暴力,对于每次询问,可以直接 \(\Theta(n^2)\) 枚举数对,用 \(ST\)表 判断一下,复杂度为 \(\Theta(qn^2)\)。

发现枚举数对没有前途,考虑 \((i,j)\) 之间的最大值,发现一个数对产生的贡献只和区间的最大值有关,我们从这个最大值入手。我们把一个数对的贡献看做其区间最大值的贡献,那么对于给定的区间,总的贡献就是区间内每个数贡献的加和,又注意到这是个排列,所以不用考虑相同数的影响。

设 \(L_i\) 表示在 \(i\) 左侧第一个大于 \(k_i\) 的值的位置,\(R_i\) 为类似的定义。那么显然 \(k_i\) 就是区间 \([L_i+1,R_i-1]\) 的最大值,那么数对 \((L_i,R_i)\) 就会产生一个 \(p_1\) 的贡献。区间 \([\max(L_i+1,l),i-1]\) 的值都会和 \(R_i\) 产生 \(p_2\) 的贡献,类似的,区间 \([i+1,\min(R_i-1,r)]\) 的值都会和 \(L_i\) 产生 \(p_2\) 的贡献,这个显然。相邻的两个数也会产生 \(p_1\) 的贡献,这个也显然。

那么直接枚举每个数,计算上述的贡献,再加和就行了,这样直接做是 \(\Theta(qn)\) 的。

Part2

考虑优化上述的算法,我们现在要统计的就是区间有多少数的 \(L_i\) 和 \(R_i\) 都在区间内,还有每个三元组 \((L_i,i,R_i)\) 产生的贡献。把这想象成一个二维平面,那么就可以看做一个二维数点问题,贡献看做是二维平面内的线或者点。

在线做的话直接上主席树就好了,需要维护区间修改,区间求和。直接永久化标记就行了。

最后别忘了相邻的数的贡献。

时间复杂度为 \(\Theta(q\log n)\)。

Code
#include <iostream>
#include <cstdio>
#include <vector>

#define int long long

const int N=2e5+10;

using namespace std;

inline int read() {
    int f=1, x=0;
    char ch=getchar();
    while(ch>'9' || ch<'0') {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9') {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return f*x; 
}

inline void write(int x) {
    cout<<x; putchar('\n');
}

int n, m, p1, p2;
int a[N], L[N], R[N], sta[N];

struct node {
    int l, r, w;
};
vector <node> p[N];

int root[N];
struct Seg_Tree {
    #define ls(k) t[k].ls
    #define rs(k) t[k].rs

    int cnt_root;
    struct Tree {
        int sum, ls, rs, tag;
    }t[N*120];

    inline int clone(int k) {
        cnt_root++;
        t[cnt_root]=t[k];
        return cnt_root;
    }
  int up_date(int k,int l,int r,int L,int R,int val) {
        k=clone(k);
        t[k].sum+=(R-L+1)*val;
        if(L==l && r==R) {
            t[k].tag+=val;
            return k;
        }
        int mid=(l+r)>>1;
        if(L>mid) rs(k)=up_date(rs(k), mid+1, r, L, R, val);
        else if(R<=mid) ls(k)=up_date(ls(k), l, mid, L, R, val);
        else {
            ls(k)=up_date(ls(k), l, mid, L, mid, val);
            rs(k)=up_date(rs(k), mid+1, r, mid+1, R, val);
        }
        return k;
    }

    int query(int u,int v,int l,int r,int L,int R) {
        if(L==l && r==R) return t[v].sum-t[u].sum;
        int mid=(l+r)>>1, sum=(t[v].tag-t[u].tag)*(R-L+1);
        if(L>mid) return sum+query(rs(u), rs(v), mid+1, r, L, R);
        else if(R<=mid) return sum+query(ls(u), ls(v), l, mid, L, R);
        else return sum+query(ls(u), ls(v), l, mid, L, mid)+
            query(rs(u), rs(v), mid+1, r, mid+1, R);
    }

    #undef ls
    #undef rs
}T;

signed main() {

    n=read(), m=read(), p1=read(), p2=read();
    for(int i=1;i<=n;i++) {
        a[i]=read();
    }

    int top=0;
    fill(R+1, R+n+1, n+1);
    for(int i=1;i<=n;i++) {
        while(top && a[i]>a[sta[top]]) {
            R[sta[top]]=i;
            top--;
        }
        L[i]=sta[top];
        sta[++top]=i;
    }

    for(int i=1;i<=n;i++) {
        if(i!=n && i+1<=R[i]-1) p[L[i]].emplace_back((node){i+1, R[i]-1, p2});
        if(L[i]+1<=i-1 && i!=1) p[R[i]].emplace_back((node){L[i]+1, i-1, p2});
        if(L[i]!=0 && R[i]!=n+1) p[R[i]].emplace_back((node){L[i], L[i], p1});
    }

    for(int i=1;i<=n;i++) {
        root[i]=root[i-1];
        for(int j=0;j<(int)p[i].size();j++) {
            node now=p[i][j];
            root[i]=T.up_date(root[i], 1, n ,now.l, now.r, now.w);
        }
    }
    
    for(int i=1;i<=m;i++) {
        int l=read(), r=read();
        int ans=T.query(root[l-1], root[r], 1, n, l, r);
        ans+=p1*(r-l);
        write(ans);
    }

    return 0;
}

标签:影魔,rs,int,top,数对,贡献,HNOI2017,区间,AH2017
From: https://www.cnblogs.com/cwymp/p/17811039.html

相关文章

  • 洛谷 P3723 [AH2017/HNOI2017]礼物
    由题面可得:\[E_j=\sum_{i=1}^{j-1}\frac{q_i}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i}{(i-j)^2}\]令\(q_0=0\),并将没有意义的分式的值视为\(0\),则有:\[E_j=\sum_{i=0}^j\frac{q_i}{(i-j)^2}-\sum_{i=j}^n\frac{q_i}{(i-j)^2}\]令\(A(i)......
  • P3723 [AH2017/HNOI2017]礼物(FFT)
    P3723[AH2017/HNOI2017]礼物(FFT)目录P3723[AH2017/HNOI2017]礼物(FFT)[AH2017/HNOI2017]礼物题目描述输入格式输出格式样例#1样例输入#1样例输出#1提示思路题意分析题目传送门[AH2017/HNOI2017]礼物题目描述我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他......
  • [AHOI2017/HNOI2017]礼物
    链接:https://www.luogu.com.cn/problem/P3723题目描述:给定两个序列,每次可以旋转其中的一个或给其中一个加上一个数\(c\),求两个序列对应位置的差的平方和所能达到的最小值......
  • [AHOI2017/HNOI2017]礼物
    链接:https://www.luogu.com.cn/problem/P3723题目描述:给定两个序列,每次可以旋转其中的一个或给其中一个加上一个数$c$,求两个序列对应位置的差的平方和所能达到的最小值。......
  • 【HNOI2017】礼物(FFT)
    显然,\(y_i\)加上\(c\)可以看成是\(x_i\)减去\(c\)。所以就变成了\(x_i\)加上一个整数(可正可负)。现将\(x\)环拆成一个长度为\(2n\)的序列\(a\)(复制一遍),把\(......