zoukankan      html  css  js  c++  java
  • LOJ2736 回转寿司

    题目蓝链

    Solution

    直接分块就可以了,对于每一块维护一个大根堆

    每次操作对于整块的部分就直接先把待替换元素压进去,然后取出堆顶的元素

    对于边界块就直接利用一个小根堆去暴力重构,然后直接依次从堆中取出最小的元素去替换就可以了,然后直接重建这个块的大根堆

    时间复杂度(mathcal{O}(q cdot sqrt n cdot log(q + sqrt n)))

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define fst first
    #define snd second
    #define squ(x) ((LL)(x) * (x))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    
    typedef long long LL;
    typedef pair<int, int> pii;
    
    inline int read() {
    	int sum = 0, fg = 1; char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    	return fg * sum;
    }
    
    const int maxn = 4e5 + 10;
    const int B = 577;
    
    priority_queue<int> pq[maxn / B + 5];
    int n, m, blks, a[maxn], S[maxn / B + 5][maxn], top[maxn / B + 5];
    
    int pos(int x) { return (x - 1) / B + 1; }
    
    void Set(int x) {
    	if (x <= 0 || x > blks) return;
    	priority_queue<int, vector<int>, greater<int> > now(S[x] + 1, S[x] + top[x] + 1);
    	int l = (x - 1) * B + 1, r = min(x * B, n);
    	for (int i = l; i <= r; i++) {
    		now.push(a[i]);
    		a[i] = now.top();
    		now.pop();
    	}
    	top[x] = 0;
    }
    
    int solve(int l, int r, int v) {
    	int x = pos(l), y = pos(r);
    	if ((l - 1) % B == 0) --x;
    	if (r % B == 0) ++y;
    	if (x == y) {
    		Set(x);
    		for (int i = l; i <= r; i++) if (a[i] > v) swap(a[i], v);
    		pq[x] = priority_queue<int>(a + (x - 1) * B + 1, a + x * B + 1);
    	} else {
    		Set(x), Set(y); int _l = x * B;
    		for (int i = l; i <= _l; i++) if (a[i] > v) swap(a[i], v);
    		pq[x] = priority_queue<int>(a + (x - 1) * B + 1, a + _l + 1);
    		++x, --y;
    		for (int i = x; i <= y; i++) {
    			if (pq[i].top() > v) {
    				pq[i].push(v);
    				S[i][++top[i]] = v;
    				v = pq[i].top();
    				pq[i].pop();
    			}
    		}
    		for (int i = y * B + 1; i <= r; i++) if (a[i] > v) swap(a[i], v);
    		pq[y + 1] = priority_queue<int>(a + y * B + 1, a + (y + 1) * B + 1);
    	}
    	return v;
    }
    
    int main() {
    	freopen("in.in", "r", stdin);
    	freopen("in.out", "w", stdout);
    
    	n = read(), m = read();
    	blks = (n - 1) / B + 1;
    
    	int cnt = 0;
    	for (int i = 1; i < blks; i++)
    		for (int j = 1; j <= B; j++)
    			pq[i].push(a[++cnt] = read());
    	for (int i = (blks - 1) * B + 1; i <= n; i++)
    		pq[blks].push(a[++cnt] = read());
    
    	while (m--) {
    		int l = read(), r = read(), v = read();
    		if (l <= r) printf("%d
    ", solve(l, r, v));
    		else printf("%d
    ", solve(1, r, solve(l, n, v)));
    	}
    
    	return 0;
    }
    

    Summary

    其实我在考试的时候已经无限接近正解了,但是在想怎么重构块的时候卡住了。我一开始以为最终序列和操作的顺序有关,所以没想到直接把所有的操作元素放到一个小根堆里就可以了

  • 相关阅读:
    记Java程序Log4J漏洞的解决过程
    IIS中应用程序池自动停止,重启报错
    如何查看域名所对应的证书有效期?
    查看前端Vue版本命令
    WCF中常见的报错:The content type text
    dotnet 将自动代码格式化机器人带入团队 GitLab 平台
    WPF 引用第三方库的控件在设计器加上设计时数据和属性
    dotnet OpenXML 聊聊文本段落对齐方式
    WPF 布局 在有限空间内让两个元素尽可能撑开的例子
    dotnet 通过 DockerfileContext 解决项目放在里层文件夹导致 VisualStudio 构建失败
  • 原文地址:https://www.cnblogs.com/xunzhen/p/9844547.html
Copyright © 2011-2022 走看看