zoukankan      html  css  js  c++  java
  • luogu 3246 莫队+RMQ+单调栈

    hnoi 2016

    标签:题解


    莫队

    考虑左端点左移以及右端点右移产生的贡献
    这样就可以由 ([l, r]) 转移到另外的 (4) 个区间
    (f_{l, r}) 表示右端点在 (r), 左端点在 ([l, r]) 内的答案,这个可以压掉一维
    (pre_{i}) 表示 (i) 前面第一个比 (a_{i}) 小的数的位置
    (bhd_{i}) 表示 (i) 后面第一个比 (a_{i}) 小的数的位置

    考虑计算贡献 (S)
    也就是右端点右移产生的贡献
    显然新增加贡献的区间的右端点只有 (r + 1)
    发现,在 ((pre_{r} + 1, r + 1]) 这段区间是单调递减的
    那么所有左端点在 ((pre_{r} + 1, r + 1]) 产生的贡献为 (a_{r + 1} * Len, Len) 表示区间长度
    我们现在另 (r2 = pre_{r}), 那么所有左端点在 ((pre_{r2} + 1, r2]) 产生的贡献为 (a_{r2} * Len)
    一直这样下去的话就会找到一个 (x) 使得 (a_{pre_{x}}) 为区间 ([l, r + 1]) 的最小值, 记 (p = pre_{x})
    记此时的总和为 (S_{1}) 就是之前的区间产生的贡献
    并且所有左端点在 ([l, p]) 产生的贡献为 (S_{2} = a_{p} imes ({p - l + 1}))
    那么

    [f_{l, r + 1} = a_{r + 1} imes (r + 1 - pre_{r + 1}) + cdots + a_{x} imes (x - pre_{x}) + f_{l, p} ]

    压掉第一维

    [f_{r + 1} = a_{r + 1} imes (r + 1 - pre_{r + 1}) + cdots + a_{x} imes (x - pre_{x}) + f_{p} ]

    增量

    [S_{2} = f_{r + 1} - f_{p} ]

    对于 (f_{i}) 预处理, (O(1)) 查询增量

    [S = S_{1} + S_{2} ]

    对于左端点左移
    对称处理 (f_{})

    #include <bits/stdc++.h>
    
    const int N = 1e5 + 10;
    
    int A[N], pos[N], size;
    int n, m;
    struct Node {
    	int l, r, id;
    	bool operator < (Node a) const {
    		if(pos[l] == pos[a.l]) return r < a.r;
    		return l < a.l;
    	}
    } Ask[N];
    int Log[N], Pow[N];
    int f[N][30];
    int Stack[N], topp, pre[N], bhd[N];
    int block;
    
    #define LL long long
    LL fl[N], fr[N], Answer[N];
    
    inline int Ask_min(int l, int r) {
    	int t = Log[r - l + 1];
    	return (A[f[l][t]] < A[f[r - Pow[t] + 1][t]] ? f[l][t] : f[r - Pow[t] + 1][t]);
    }
    
    inline LL Left(int l, int r) {
    	int p = Ask_min(l - 1, r);
    	return 1ll * A[p] * (r - p + 1) + fl[l - 1] - fl[p];
    }
    
    inline LL Right(int l, int r) {
    	int p = Ask_min(l, r + 1);
    	return 1ll * A[p] * (p - l + 1) + fr[r + 1] - fr[p];
    }
    
    #define Rep(i, a, n) for(int i = a; i <= n; i ++)
    
    int main() {
    	std:: cin >> n >> m;
    	for(int i = 1; i <= n; i ++) std:: cin >> A[i];
    	A[0] = A[n + 1] = (1 << 30);
    	for(int i = 1; i <= m; i ++) {
    		std:: cin >> Ask[i].l >> Ask[i].r;
    		Ask[i].id = i;
    	}
    	block = sqrt(n);
    	for(int i = 1; i <= n; i ++) pos[i] = (i - 1) / block + 1;
    	for(int i = 1; i <= n; i ++) f[i][0] = i;
    	std:: sort(Ask + 1, Ask + m + 1);
    	for(int i = 0; (Pow[i] = (1 << i)) <= n; i ++);
    	for(int i = 2; i <= n; i ++) Log[i] = Log[i >> 1] + 1;
    	for(int i = 1; Pow[i] <= n; i ++)
    		for(int j = 1; j <= n - Pow[i - 1] + 1; j ++)
    			f[j][i] = (A[f[j][i - 1]] > A[f[j + Pow[i - 1]][i - 1]] ? f[j + Pow[i - 1]][i - 1] : f[j][i - 1]);
    	for(int i = 1; i <= n; i ++) {
    		while(topp && A[Stack[topp]] > A[i]) {
    			bhd[Stack[topp]] = i;
    			topp --;
    		}
    		pre[i] = Stack[topp];
    		Stack[++ topp] = i;
    	}
    	while(topp) bhd[Stack[topp --]] = n + 1;
    	for(int i = 1; i <= n; i ++) fr[i] = fr[pre[i]] + 1ll * A[i] * (i - pre[i]);
    	for(int i = n; i >= 1; i --) fl[i] = fl[bhd[i]] + 1ll * A[i] * (bhd[i] - i);
    	int l = 1, r = 0;
    	LL Ans = 0;
    	for(int i = 1; i <= m; i ++) {
    		int x = Ask[i].l, y = Ask[i].r;
    		while(l > x) Ans += Left(l, r), l --;
    		while(r < y) Ans += Right(l, r), r ++;
    		while(l < x) Ans -= Left(l + 1, r), l ++;
    		while(r > y) Ans -= Right(l, r - 1), r --;
    		Answer[Ask[i].id] = Ans;
    	}
    	for(int i = 1; i <= m; i ++) std:: cout << Answer[i] << "
    ";
    	return 0;
    }
    
    
  • 相关阅读:
    centos 6.5安装erlang和RabbitMQ
    vert.x学习(八),用JDBCClient配合c3p0操作数据库
    vert.x学习(七),使用表单获取用户提交的数据
    vert.x学习(六),动态模板与静态文件的结合
    vert.x学习(五),用StaticHandler来处理静态文件
    函数-生成器、迭代器
    函数装饰器
    函数参数、作用域、高阶函数、递归函数、高阶函数
    深浅拷贝、集合set、函数、日志
    第一部分day5 文件操作
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9678985.html
Copyright © 2011-2022 走看看