zoukankan      html  css  js  c++  java
  • 【LG3722】[HNOI2017]影魔

    【LG3722】[HNOI2017]影魔

    题面

    洛谷

    题解

    先使用单调栈求出(i)左边第一个比(i)大的位置(lp_i),和右边第一个比(i)大的位置(rp_i)

    考虑(i)对答案的贡献,当且仅当(i)作为区间([x+1,y-1])的最大值时,(i)才对点对((x,y))有贡献。

    根据题意,第一种情况(i)产生贡献的点对是((lp_i,rp_i))

    第二种情况(i)产生贡献的点对是((l[i],i+1) to (r[i]-1))((r[i],l[i]+1) to (i-1))

    同时还要加上特殊情况((i,i+1))

    问题便转化为在二维平面上,有一些线段被涂色(点算作特殊的包含点数为1的线段),问一个矩形区域内的涂色的点的个数。

    常用做法是扫描线,但是我写的是主席树。

    发现点对的第一个点都是固定的,所以我们可以以第一个点为根建立可持久化线段树,并在对应的可持久化线段树上进行区间更新,并且标记永久化即可。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    inline int gi() {
        register int data = 0, w = 1;
        register char ch = 0;
        while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
        if (ch == '-') w = -1 , ch = getchar();
        while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
        return w * data;
    }
    typedef long long ll; 
    #define MAX_N 200005
    
    int N, M, P1, P2, a[MAX_N]; 
    int st[MAX_N], top, lp[MAX_N], rp[MAX_N];
    struct data {
    	int x, l, r; 
    	ll p;
    	data() {} 
    	data(int _x, int _l, int _r, ll _p) { l = _l, r = _r, x = _x, p = _p; }
    	bool operator < (const data &rhs) const {
    		return x < rhs.x; 
    	} 
    } v[MAX_N << 2]; 
    int cnt = 0;
    struct Node {
    	int ls, rs;
    	ll s, tag; 
    } t[MAX_N << 6]; 
    int rt[MAX_N], tot;
    void build(int &x, int l, int r) {
    	x = ++tot; 
    	if (l == r) return ;
    	int mid = (l + r) >> 1;
    	build(t[x].ls, l, mid); build(t[x].rs, mid + 1, r); 
    } 
    void insert(int &x, int y, int l, int r, int ql, int qr, ll v) {
    	x = ++tot; t[x] = t[y]; t[x].s = t[y].s + (qr - ql + 1) * v; 
    	if (ql == l && r == qr) { t[x].tag += v; return ; } 
    	int mid = (l + r) >> 1;
    	if (qr <= mid) insert(t[x].ls, t[y].ls, l, mid, ql, qr, v); 
    	else if (ql > mid) insert(t[x].rs, t[y].rs, mid + 1, r, ql, qr, v);
    	else insert(t[x].ls, t[y].ls, l, mid, ql, mid, v), insert(t[x].rs, t[y].rs, mid + 1, r, mid + 1, qr, v); 
    }
    ll query(int u, int v, int l, int r, int ql, int qr) {
    	if (ql <= l && r <= qr) return t[u].s - t[v].s;
    	int mid = (l + r) >> 1;
    	ll res = (t[u].tag - t[v].tag) * (qr - ql + 1);
    	if (qr <= mid) return query(t[u].ls, t[v].ls, l, mid, ql, qr) + res; 
    	else if (ql > mid) return query(t[u].rs, t[v].rs, mid + 1, r, ql, qr) + res;
    	else return res + query(t[u].ls, t[v].ls, l, mid, ql, mid) + query(t[u].rs, t[v].rs, mid + 1, r, mid + 1, qr); 
    } 
    int main () { 
    	N = gi(), M = gi(), P1 = gi(), P2 = gi();  
    	for (int i = 1; i <= N; i++) a[i] = gi(); 
    	top = 0;
    	for (int i = 1; i <= N; i++) {
    		while (top && a[st[top]] < a[i]) --top; 
    		lp[i] = st[top], st[++top] = i; 
    	} 
    	top = 0;
    	for (int i = N; i >= 1; i--) { 
    		while (top && a[st[top]] < a[i]) --top;
    		rp[i] = top ? st[top] : (1 + N), st[++top] = i; 
    	}
    	for (int i = 1; i <= N; i++) {
    		if (lp[i] != 0 && rp[i] != N + 1) v[++cnt] = data(lp[i], rp[i], rp[i], P1);
    		if (i < N) v[++cnt] = data(i, i + 1, i + 1, P1);
    		if (lp[i] != 0 && rp[i] - i > 1) v[++cnt] = data(lp[i], i + 1, rp[i] - 1, P2);
    		if (rp[i] != N + 1 && i - lp[i] > 1) v[++cnt] = data(rp[i], lp[i] + 1, i - 1, P2); 
    	}
    	sort(&v[1], &v[cnt + 1]);
    	build(rt[0], 1, N); 
    	for (int i = 1, j = 1; i <= N; i++) { 
    		rt[i] = rt[i - 1];
    		while (j <= cnt && v[j].x == i)
    			insert(rt[i], rt[i], 1, N, v[j].l, v[j].r, v[j].p), j++; 
    	}
    	while (M--) {
    		int l = gi(), r = gi();
    		printf("%lld
    ", query(rt[r], rt[l - 1], 1, N, l, r)); 
    	} 
    	return 0; 
    } 
    
  • 相关阅读:
    SQL Server Management Studio
    uiimage拉伸
    时间空间复杂度
    冒泡选择排序

    插入排序
    快速构建APP
    TTTAtibutedlabel
    Git命令
    适配
  • 原文地址:https://www.cnblogs.com/heyujun/p/10447568.html
Copyright © 2011-2022 走看看