• [HNOI2017] 影魔


    Description

    Portal

    一句话题意:给定n个数的排列,m次询问,每次询问询问一个区间内所有子区间的贡献。
    每个区间如果两个端点分别是最大值次大值,我们就算P1的贡献。
    如果两个端点一个是最大值,一个不是次大值,我们就算P2的贡献。

    $ n, m leq 200009 $

    Solution

    这题其实是除了礼物之外的HNOI的最容易的题目

    因为要处理两个端点的值, 所以我们钦定某一个端点为最大值(这里钦定右端点)
    ,同时处理另一个端点的情况。

    那么如果要计算左端点是最大值,那么只要把序列反转然后重新计算一次。

    考虑计算一个点的值。如果某个点是从右端点出发的当前的最大值。
    那么这个点x要和右端点计算P1的贡献。这个点之前到上个最大点之后的点全部计算P2的贡献。
    这个可以用个单调栈来维护。

    最后还有一部分细节: 在单调栈弹完的时候,必须要把之前的弹出的没处理的元素加上P2的贡献。

    Inspiration

    在询问两个端点都有要求的时候,我们可以考虑一个固定端点然后处理。
    查询两遍即可。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
    #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
    #define clar(a, b) memset((a), (b), sizeof(a))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    typedef long long LL;
    typedef long double LD;
    int read() {
        char ch = getchar();
        int x = 0, flag = 1;
        for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
        for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
        return x * flag;
    }
    void write(int x) {
        if (x < 0) putchar('-'), x = -x;
        if (x >= 10) write(x / 10);
        putchar(x % 10 + 48);
    }
    
    const int Maxn = 2e5 + 9;
    int n, m, a[Maxn], p1, p2;
    vector <pair<int, int> > querySeq[Maxn], seq;
    LL ans[Maxn];
    
    void init() {
    	n = read(), m = read(), p1 = read(), p2 = read();
    	rep (i, 1, n) a[i] = read();
    	rep (i, 1, m) {
    		int l = read(), r = read();
    		seq.push_back(make_pair(l, r));
    	}
    }
    
    namespace SGMTtree {
    	LL tree[Maxn << 3], add[Maxn << 3];
    
    #define lc(x) ((x) << 1)
    #define rc(x) ((x) << 1 | 1)
    #define ls rt << 1, l, mid
    #define rs rt << 1 | 1, mid + 1, r
    
    	inline LL getTree(int rt) { return tree[rt];}
    	LL (*get)(int);
    
    	inline void setAdd(int rt, int l, int r, int v) { 
    		add[rt] += v;
    		tree[rt] += (r - l + 1ll) * v;
    	}
    	void (*setTag)(int, int, int, int);
    	void init(int modif, int quer) { 
    		clar(tree, 0); 
    		clar(add, 0); 
    		if (modif == 1) setTag = setAdd;
    		if (quer == 1) get = getTree;
    	}
    
    	inline void pushup(int rt) { tree[rt] = tree[lc(rt)] + tree[rc(rt)]; }
    	inline void pushdown(int rt, int l, int r) {
    		int mid = (l + r) >> 1;
    		if (add[rt]) {
    			setAdd(lc(rt), l, mid, add[rt]);
    			setAdd(rc(rt), mid + 1, r, add[rt]);
    			add[rt] = 0;
    		}
    	}
    
    	void modify(int rt, int l, int r, int p, int q, int v) {
    		if (p > q) return ;
    		if (p <= l && r <= q) {
    			setTag(rt, l, r, v);
    			return ;
    		}
    		int mid = (l + r) >> 1; pushdown(rt, l, r);
    		if (q <= mid)  modify(ls, p, q, v);
    		else if (p >= mid + 1)  modify(rs, p, q, v);
    		else modify(ls, p, q, v), modify(rs, p, q, v);
    		pushup(rt);
    	} 
    	LL query(int rt, int l, int r, int p, int q) {
    		if (p > q) return 0;
    		if (p <= l && r <= q) return get(rt);
    
    		int mid = (l + r) >> 1; pushdown(rt, l, r);
    
    		if (q <= mid) return query(ls, p, q);
    		else if (p >= mid + 1) return query(rs, p, q);
    		else return query(ls, p, q) + query(rs, p, q);
    	}
    
    #undef lc
    #undef rc
    #undef ls
    #undef rs
    }
    
    void duce() {
    	stack <int> s;
    	SGMTtree :: init(1, 1);
    	rep (i, 1, n) {
    		int _lst = i;
    		while (!s.empty() && a[s.top()] <= a[i]) {
    			if (s.top() + 1 < _lst) SGMTtree :: modify(1, 1, n, s.top() + 1, _lst - 1, p2);
    			SGMTtree :: modify(1, 1, n, s.top(), s.top(), p1);
    			_lst = s.top(); s.pop();
    		}
    		if (s.empty()) SGMTtree :: modify(1, 1, n, 1, _lst - 1, p2);
    		else SGMTtree :: modify(1, 1, n, s.top() + 1, _lst - 1, p2);
    		s.push(i);
    		rep (j, 0, querySeq[i].size() - 1) 
    			ans[querySeq[i][j].second] += SGMTtree :: query(1, 1, n, querySeq[i][j].first, i);
    	}
    }
    
    void solve() {
    	rep (i, 0, m - 1)	querySeq[seq[i].second].push_back(make_pair(seq[i].first, i + 1));
    	rep (i, 1, n) sort(querySeq[i].begin(), querySeq[i].end());
    	duce();
    
    	rep (i, 1, n) querySeq[i].clear();
    	rep (i, 0, m - 1) querySeq[n - seq[i].first + 1].push_back(make_pair(n - seq[i].second + 1, i + 1));
    	rep (i, 1, n) sort(querySeq[i].begin(), querySeq[i].end());
    	reverse(a + 1, a + n + 1);
    	duce();
    
    	rep (i, 1, m) printf("%lld
    ", ans[i]);
    }
    
    int main() {
    	freopen("LG3722.in", "r", stdin);
    	freopen("LG3722.out", "w", stdout);
    
    	init();
    	solve();
    
    #ifdef Qrsikno
        debug("
    Running time: %.3lf(s)
    ", clock() * 1.0 / CLOCKS_PER_SEC);
    #endif
        return 0;
    }
    
    
    
  • 相关阅读:
    EF5+MVC4系列(5) 删除的方法 1:系统推荐的先查询后remove删除的方法 2:自己new一个包含主键的类,然后 attach附加 remove删除;3:使用db.Entry 修改状态删除4:EntityState的几种状态
    指定webapi 返回 json 格式 ; GlobalConfiguration.Configuration.Formatters.Clear()
    远程桌面连接工具 Remote Desktop Manager 9.1.2.0 Enterprise 多国语言绿色版附注册码 简单使用
    .NET WebAPI 正确抛出错误详细信息
    观察者模式 发布订阅者模式
    7月目标 socket , 一致性哈希算法 ; mongodb分片; 分布式消息队列; 中间件的使用场景
    在js中 把 json对象转化为String对象的方法
    mvc4中的 webapi 的使用方式
    Uncaught TypeError: TableInit is not a constructor
    Jquery复选框操作
  • 原文地址:https://www.cnblogs.com/qrsikno/p/10060431.html
Copyright © 2020-2023  润新知