• LOJ 6057


    Description

    给定一个长度为 (nle 3*10^6) 的序列
    (qle 10^7) 次询问每次求区间 ([l,r]) 的所有子区间的最小值的和
    询问随机

    Solution

    考虑求出区间的最小值, 设在位置 (p)
    考虑 ([l, p))((p, r]) 的答案
    ([l, p) = [l, n] - [p, n] - (左端点在[l, p) 右端点在[p, n] 的))
    因为 ([l, p)) 都比 (p)
    所以该部分为 ((p-l) * 左端点在p的答案)

    区间最小值可以用rmq求
    正常的O(n)-O(1) rmq需要转成树, 然后变成 (pm 1) 的, 然后分块块内还要预处理, 常数很大
    注意到这题询问随机, 询问到块内的几率很小, 所以可以把块内的处理改成暴力
    块边缘维护前后缀min即可

    Code

    #include <bits/stdc++.h>
    using namespace std;
    #define ri rd<int>
    #define rep(i, a, b) for (int i = (a), _ = (b); i <= _; ++i)
    #define per(i, a, b) for (int i = (a), _ = (b); i >= _; --i)
    #define For(i, a, b) for (int i = (a), _ = (b); i < _; ++i)
    const int maxN = 3e6 + 7;
    const int INF = 1e9 + 7;
    typedef long long LL;
    const LL O = 1e9 + 7;
    
    template<class T> T rd() {
    	bool f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = 0;
    	T x = 0; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; return f ? x : -x;
    }
    
    int n, m;
    int a[maxN];
    
    namespace IO {
    	int A, B, C, P;
    	LL lastAns;
    
    	inline int rnd() {
    		return A = (A * B + (C ^ (int)(lastAns & 0x7fffffffLL)) % P) % P;	
    	}
    
    	void init() {
    		A = ri(), B = ri(), C = ri(), P = ri();
    		lastAns = 0;
    	}
    }
    
    namespace RMQ {
    	const int maxL = 3e5 + 7;
    	const int B = 12;
    	struct Node {
    		int l, r, v;
    		int pre[12], suf[12];
    	}a[maxL];
    
    	int st[maxL][20];
    	int ln[maxL];
    	int bl[maxN];
    
    	void gmin(int &x, int y) {
    		if (::a[y] < ::a[x]) x = y;
    	}
    
    	int ggmin(int x, int y) {
    		return ::a[x] < ::a[y] ? x : y;
    	}
    
    	void init() {
    		rep (i, 1, n) {
    			int &t = bl[i] = i / B;
    			int &v = st[t][0];
    			if (a[t].l == 0) {
    				a[t].l = i;
    				v = i;
    			}
    			a[t].r = i;
    			gmin(v, i);
    		}
    
    		int T = bl[n];
    		rep (j, 0, T) {
    			Node &t = a[j];
    			int l = t.l, r = t.r;
    			t.pre[0] = l;
    			rep (i, l+1, r) t.pre[i-l] = ggmin(t.pre[i-l-1], i);
    			t.suf[0] = r;
    			per (i, r-1, l) t.suf[r-i] = ggmin(t.suf[r-i-1], i);
    		}
    
    		rep (i, 2, T) ln[i] = ln[i >> 1] + 1;
    		per (i, T, 0) {
    			rep (j,	1, ln[T-i+1])
    				st[i][j] = ggmin(st[i][j-1], st[i+(1<<(j-1))][j-1]);
    		}
    	}
    
    	int eval(int l, int r) {
    		int len = ln[r-l+1];
    		return ggmin(st[l][len], st[r-(1<<len)+1][len]);
    	}
    
    	int get(int l, int r) {
    		int res = l;
    		if (bl[l] == bl[r]) {
    			rep (i, l, r) gmin(res, i);
    			return res;
    		}
    		int u = bl[l], v = bl[r];
    		gmin(res, a[u].suf[a[u].r - l]);
    		gmin(res, a[v].pre[r - a[v].l]);
    		if (u+1 < v) gmin(res, eval(u+1, v-1));
    		return res;
    	}
    }
    
    namespace Solve {
    	LL pre[maxN], suf[maxN];
    
    	void init() {
    		static int stack[maxN], Top;
    		stack[Top = 0] = 0;
    		LL res = 0;
    		rep (i, 1, n) {
    			for (; Top && a[stack[Top]] >= a[i]; --Top)
    				res -= 1LL * a[stack[Top]] * (stack[Top] - stack[Top-1]);
    			stack[++Top] = i;
    			res += 1LL * a[i] * (stack[Top] - stack[Top-1]);
    			pre[i] = res;
    		}
    		res = 0;
    		per (i, n, 1) {
    			for (; Top && a[stack[Top]] >= a[i]; --Top)
    				res -= 1LL * a[stack[Top]] * (stack[Top-1] - stack[Top]);
    			stack[++Top] = i;
    			res += 1LL * a[i] * (stack[Top-1] - stack[Top]);
    			suf[i] = res;
    		}
    		rep (i, 1, n) pre[i] += pre[i-1];
    		per (i, n, 1) suf[i] += suf[i+1];
    	}
    
    	LL getr(int l, int r) {
    		return suf[l] - suf[r] - 1LL * (r-l) * (suf[r] - suf[r+1]);
    	}
    
    	LL getl(int l, int r) {
    		return pre[r] - pre[l] - 1LL * (r-l) * (pre[l] - pre[l-1]);
    	}
    }
    
    LL get(int l, int r) {
    	int p = RMQ::get(l, r);	
    	LL res = 1LL * (p-l+1) * (r-p+1) * a[p];
    	if (l < p) res += Solve::getr(l, p);
    	if (p < r) res += Solve::getl(p, r);
    	return res;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("a.in", "r", stdin);
    #endif
    
    	n = ri(), m = ri();
    	rep (i, 1, n) a[i] = ri();
    	IO::init();
    	RMQ::init();
    	Solve::init();
    
    	LL res = 0;
    	rep (i, 1, m) {
    		int l = IO::rnd() % n + 1, r = IO::rnd() % n + 1;
    		if (l > r) std::swap(l, r);
    		LL &tp = IO::lastAns = get(l, r);
    		res += tp % O;
    	}
    	printf("%lld
    ", (res % O + O) % O);
    
    	return 0;
    }
    
  • 相关阅读:
    poj1087最大流拆点
    3月15上午的函数练习
    3月15
    3月13上午
    3月13
    3月12
    break语句
    3月11
    3月10号
    3月9号
  • 原文地址:https://www.cnblogs.com/acha/p/9037573.html
Copyright © 2020-2023  润新知