zoukankan      html  css  js  c++  java
  • HNOI2017影魔

    (HNOI2017影魔)

    • 首先有(p1)贡献的区间能发现只有(O(n))个, 具体地,将数字从大到小插入区间,只有这个数的((位置的))前驱后继才有贡献,所以第一部分将询问放在右端点,扫描线就能做
    • 对于有(p2)贡献的区间,考虑枚举中间最大的数,即求出(L[i], R[i]),表示左边右边第一个大于它的位置,
      • 具体地只考虑第一种情况即(a[l] < a[mid] < a[r]),第二种情况类似,发现只有(lin(L[i],i), r = R[i])的区间有贡献,把这些区间都存在右端点, 最后一起取并,直接同上的扫描线做一遍
    • 代码写的有点长, 但好歹能过?
    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define SZ(x) ((int) ((x).size()))
    #define fst first
    #define snd second
    
    typedef pair<int, int> pii;
    typedef long long ll;
    
    inline int read(int x = 0, int _f = 0)
    {
    	char c = getchar();
    	for (; !isdigit(c); c = getchar()) 
    		_f |= (c == '-');
    	for (;  isdigit(c); c = getchar()) 
    		x = x*10 + c-'0';
    	return _f? -x : x;
    }
    template <typename T> bool chkmax(T &a, T b) 
    {
    	return a < b? a = b, true : false; 
    }
    template <typename T> bool chkmin(T &a, T b) 
    {
    	return a > b? a = b, true : false; 
    }
    
    const int N = 2e5 + 5;
    
    int n, q, p1, p2;
    
    int A[N], P[N];
    
    struct Query
    {
    	int l, r, id;
    	Query(int l = 0, int r = 0, int id = 0) : l(l), r(r), id(id) {}
    }qry[N];
    
    vector<pii> deal[N], arr[N];
    
    ll ans[N];
    
    int R[N], L[N];
    
    struct SegmentTree
    {
    #define mid ((l + r) >> 1)
    #define lc (h << 1)
    #define rc (lc | 1)
    
    ll sum[N << 2], addv[N << 2];
    
    inline void clear(int n)
    {
    	for (int i = 1; i <= n << 2; ++i) {
    		sum[i] = addv[i] = 0;
    	}
    }
    
    inline void push_down(int h, int l, int r)
    {
    	if (addv[h]) {
    		sum[lc] += addv[h] * (mid - l + 1), addv[lc] += addv[h];
    		sum[rc] += addv[h] * (r - mid), addv[rc] += addv[h];
    		addv[h] = 0;
    	}
    }
    
    void modify(int h, int l, int r, int ql, int qr)
    {
    	if (ql <= l && r <= qr) {
    		sum[h] += r - l + 1; addv[h] ++;
    		return ;
    	}
    
    	push_down(h, l, r);
    
    	if (ql <= mid) modify(lc, l, mid, ql, qr);
    	if (qr > mid) modify(rc, mid + 1, r, ql, qr);
    
    	sum[h] = sum[lc] + sum[rc];
    }
    
    ll query(int h, int l, int r, int ql, int qr)
    {
    	if (qr < ql) return 0;
    
    	if (ql <= l && r <= qr) return sum[h];
    	push_down(h, l, r);
    	return (ql <= mid? query(lc, l, mid, ql, qr) : 0) +
    		(qr > mid? query(rc, mid + 1, r, ql, qr) : 0);
    }
    
    #undef lc
    #undef rc
    #undef mid
    }SEGT1, SEGT2;
    
    void combine(vector<pii> &A)
    {
    	vector<pii> tmp = A; A.clear();
    	sort(tmp.begin(), tmp.end());
    
    	int l = 0, r = -1;
    	for (int j = 0; j < SZ(tmp); ++j) {
    		if (j && tmp[j].fst <= r) {
    			chkmax(r, tmp[j].snd);
    		}
    		else {
    			if (l <= r) A.push_back(pii(l, r));
    			l = tmp[j].fst;
    			r = tmp[j].snd;
    		}
    	}
    	if (l <= r) A.push_back(pii(l, r));
    }
    
    void exec()
    {
    	set<int> pos;
    
    	for (int i = n; i >= 1; --i) {
    		auto it = pos.insert(P[i]).fst;
    
    		if (it != pos.begin()) {
    			deal[*it].push_back(pii(*prev(it), 1));
    //			printf("[%d, %d]
    ", *prev(it), *it);
    			L[P[i]] = *prev(it);
    		}
    		if (it != --pos.end()) {
    			deal[*next(it)].push_back(pii(*it, 1));
    //			printf("[%d, %d]
    ", *it, *next(it));
    			R[P[i]] = *next(it);
    		}
    	}
    
    	for (int i = 1; i <= q; ++i) {
    		deal[qry[i].r].push_back(pii(i, 0));
    	}
    
    	for (int i = 1; i <= n; ++i) if (R[i]) {
    		if (L[i] + 1 < i) arr[R[i]].push_back(pii(L[i] + 1, i - 1));
    	}
    
    	for (int i = 1; i <= n; ++i) combine(arr[i]);
    
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 0; j < SZ(arr[i]); ++j) {
    			SEGT2.modify(1, 1, n, arr[i][j].fst, arr[i][j].snd);
    		}
    		for (int j = 0; j < SZ(deal[i]); ++j) {
    			if (!deal[i][j].snd) {
    				int o = deal[i][j].fst;
    				ans[qry[o].id] += SEGT2.query(1, 1, n, qry[o].l, qry[o].r-1) * p2;
    				ans[qry[o].id] += SEGT1.query(1, 1, n, qry[o].l, qry[o].r-1) * p1;
    			}
    			else {
    				SEGT1.modify(1, 1, n, deal[i][j].fst, deal[i][j].fst);
    			}
    		}
    	}
    }
    
    void repeatP2()
    {
    	SEGT2.clear(n);
    	for (int i = 1; i <= n; ++i) arr[i].clear(), deal[i].clear();
    
    	for (int i = 1; i <= q; ++i) {
    		deal[qry[i].l].push_back(pii(i, 0));
    	}
    
    	for (int i = 1; i <= n; ++i) if (L[i]) {
    		if (i + 1 < R[i]) {
    			arr[L[i]].push_back(pii(i + 1, R[i] - 1));
    		}
    	}
    
    	for (int i = 1; i <= n; ++i) combine(arr[i]);
    
    	for (int i = n; i >= 1; --i) {
    		for (int j = 0; j < SZ(arr[i]); ++j) {
    			SEGT2.modify(1, 1, n, arr[i][j].fst, arr[i][j].snd);
    		}
    		for (int j = 0; j < SZ(deal[i]); ++j) {
    			int o = deal[i][j].fst;
    			ans[qry[o].id] += SEGT2.query(1, 1, n, qry[o].l+1, qry[o].r) * p2;
    		}
    	}
    }
    
    int main()
    {
    	freopen("sf.in", "r", stdin);
    	freopen("sf.out", "w", stdout);
    
    	n = read(), q = read(); p1 = read(), p2 = read();
    
    	for (int i = 1; i <= n; ++i) {
    		A[i] = read();
    		P[A[i]] = i;
    		L[i] = 0, R[i] = n + 1;
    	}
    
    	for (int i = 1; i <= q; ++i) {
    		int l = read(), r = read();
    		qry[i] = Query(l, r, i);
    	}
    
    	exec(); 
    	repeatP2();
    
    	for (int i = 1; i <= q; ++i) {
    		printf("%lld
    ", ans[i]);
    	}
    
    	return 0;
    }
    
    
  • 相关阅读:
    分布式监控系统开发【day38】:报警自动升级代码解析及测试(八)
    分布式监控系统开发【day38】:报警阈值程序逻辑解析(四)
    分布式监控系统开发【day38】:监控trigger表结构设计(一)
    ubuntu 14.04 gitlab 的搭建
    u-boot2011.09 u-boot.img 的流程跟踪
    am335x u-boot2011.09 SPL 流程跟踪
    ubuntu apt-get 安装指定版本软件
    am335x Lan8710a 双网口配置
    Linux 使用tty0 显示10分钟自动关闭功能
    am335x uboot, kernel 编译
  • 原文地址:https://www.cnblogs.com/pbvrvnq/p/8672872.html
Copyright © 2011-2022 走看看