JZOJ 5967. 常数国

题解:

对于这种题还是要从部分分的做法下手。

如果操作都是[1…n],我们并不用关心具体的变化,每次都是取出最大值,然后插入一个值,显然用个堆就行了。

对于100分也是类似的,观察时限和数据范围,不难想到分块。

对于整块的,只要取出最大值,插入一个值,还要打上一个标记,表示插入个这个值。

因为在处理散块的时候,需要先把序列还原出来,那么就是标记如何下传的问题了。

首先不然想到标记之间的顺序没有关系,因为大的一定会在后面被小的覆盖,所以从左到右枚举,对于这个位置的值,与标记中最小的判断就行了。

常数感人。

Code:

#pragma GCC optimize(2)
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define gc getchar
#define pc putchar
#define pb push_back
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;

const int N = 4e5 + 5, M = 650;

int n, Q, x, y, z, a[N], ii;
int bl[N], l[N / M + 50], r[N / M + 50], m;
priority_queue<int> q[N / M + 50], eq;

struct nod { int y; nod(int _y = 0) {y = _y;}};
bool operator <(nod a, nod b) { return a.y > b.y;}
priority_queue<nod> d[N], ed;

void sf(int x) {
    fo(i, l[x], r[x]) {
    	if(d[x].empty()) break;
    	if(d[x].top().y < a[i]) d[x].push(nod(a[i])), a[i] = d[x].top().y, d[x].pop();
    }
    d[x] = ed;
}

int bins(int x, int y, int z) {
    sf(bl[x]);
    fo(i, x, y) if(a[i] > z) swap(a[i], z);
    q[bl[x]] = eq;
    fo(i, l[bl[x]], r[bl[x]])
		q[bl[x]].push(a[i]);
    return z;
}

int calc(int x, int y, int z) {
    if(bl[x] == bl[y]) {
        return bins(x, y, z);
    } else {
        z = bins(x, r[bl[x]], z);
        fo(j, bl[x] + 1, bl[y] - 1) {
        	int p = q[j].top();
            if(p > z) {
            	d[j].push(nod(z));
                int z0 = z; z = p;
				q[j].pop(); q[j].push(z0);
            }
        }
        return bins(l[bl[y]], y, z);
    }
}

void read(int &x) {
	char c = ' '; x = 0;
	while(c < '0' || c > '9') c = gc();
	for(; c >= '0' && c <= '9'; c = gc()) x = x * 10 + c - 48;
}

void write(int x) {
	if(!x) {pc('0'); return;}
	int d[10]; d[0] = 0;
	for(; x; x /= 10) d[++ d[0]] = x % 10;
	while(d[0]) pc(d[d[0] --] + 48);
}

int main() {
    freopen("in.in", "r", stdin);
    freopen("in.out", "w", stdout);
    scanf("%d %d", &n, &Q);
    fo(i, 1, n) {
        bl[i] = bl[i - 1];
        if(i % M == 1) r[bl[i]] = i - 1, l[++ bl[i]] = i; 
    } r[m = bl[n]] = n;
    fo(i, 1, n) read(a[i]);
    fo(i, 1, n) q[bl[i]].push(a[i]);
    for(ii = 1; ii <= Q; ii ++) {
    	read(x); read(y); read(z);
        if(x <= y) write(calc(x, y, z)); else
        	write(calc(1, y, calc(x, n, z)));
        pc('\n');
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值