luogu P4119 [Ynoi2018] 未来日记
https://www.luogu.com.cn/problem/P4119
第一次感觉自己代码写得好优美,吹爆(bushi)
直接考虑最暴力的分块,序列分块+值域分块
设表示前块,值域在第块的有几个
表示前块,值域为的有多少个
然后查询就可以直接暴力找出位于那一值域块里(用),然后再一个个暴力找(用)
散块暴力重构即可
考虑修改,散块暴力修改,对于整块,如果都有可以直接暴力把整个块扫一遍,把全部改成, 因为每次修改必定会使得其中一种消失,均摊下来是正确的(增多的情况也最多只会把两块的种类增多一个)
否则对于这块如果不存在的话直接把的编号设为的编号,然后把的删掉即可
具体实现可以参考代码,保证看得懂!!1
code:
#include<bits/stdc++.h>
#define blo 320
#define N 100050
#define M 325
#define L(x) ((x - 1) * blo + 1)
#define R(x) (min(x * blo, n))
using namespace std;
inline int rd() {
int x = 0; char ch = getchar();
for(; ch < '0' || ch > '9' ;) ch = getchar();
for(; ch >= '0' && ch <= '9'; ) x = (x << 3) + (x << 1) + (ch - '0'), ch = getchar();
return x;
}
int lim = 100000;
int a[N], b[N], cnt[M][N], bcnt[M][M], ys[M][blo + 5], bh[M][N], bel[N], n, q, m, bm;
void pushdown(int id) {
for(int i = L(id); i <= R(id); i ++) a[i] = ys[id][b[i]];
}
void change(int id, int x, int y) {
int o = bh[id][x];
bh[id][y] = o;
ys[id][o] = y;
bh[id][x] = 0;
}
void build(int id) {
int gs = 0;
for(int i = 1; i <= blo; i ++) bh[id][ys[id][i]] = 0;
for(int i = L(id); i <= R(id); i ++) {
if(!bh[id][a[i]]) {
bh[id][a[i]] = ++ gs;
ys[id][gs] = a[i];
}
}
for(int i = L(id); i <= R(id); i ++) b[i] = bh[id][a[i]];
}
void init() {
for(int i = 1; i <= lim; i ++) bel[i] = (i - 1) / blo + 1;
m = bel[n]; bm = bel[lim];
for(int i = 1; i <= n; i ++) {
int id = bel[i];
cnt[id][a[i]] ++;
bcnt[id][bel[a[i]]] ++;
}
for(int i = 1; i <= m; i ++) {
build(i);
for(int j = 1; j <= lim; j ++) cnt[i][j] += cnt[i - 1][j];
for(int j = 1; j <= bm; j ++) bcnt[i][j] += bcnt[i - 1][j];
}
}
void chan(int l, int r, int x, int y) {
if(x == y) return ;
int bl = bel[l], br = bel[r];
int bx = bel[x], by = bel[y];
if(cnt[br][x] - cnt[bl - 1][x] == 0) return ;
int f = 0;
if(bx == by) f = 1;
for(int i = m; i > 1; i --) {
cnt[i][x] -= cnt[i - 1][x];
cnt[i][y] -= cnt[i - 1][y];
if(!f) bcnt[i][bx] -= bcnt[i - 1][bx], bcnt[i][by] -= bcnt[i - 1][by];
}
if(bl == br) {
pushdown(bl);
for(int i = l; i <= r; i ++) {
if(a[i] == x) {
a[i] = y;
cnt[bl][x] --, cnt[bl][y] ++;
if(!f) bcnt[bl][bx] --, bcnt[bl][by] ++;
}
}
build(bl);
} else {
pushdown(bl), pushdown(br);
for(int i = l; i <= R(bl); i ++) {
if(a[i] == x) {
a[i] = y;
cnt[bl][x] --, cnt[bl][y] ++;
if(!f) bcnt[bl][bx] --, bcnt[bl][by] ++;
}
}
for(int i = L(br); i <= r; i ++) {
if(a[i] == x) {
a[i] = y;
cnt[br][x] --, cnt[br][y] ++;
if(!f) bcnt[br][bx] --, bcnt[br][by] ++;
}
}
build(bl), build(br);
for(int i = bl + 1; i < br; i ++) {
if(cnt[i][x]) {
if(cnt[i][y]) {
pushdown(i);
for(int j = L(i); j <= R(i); j ++) {
if(a[j] == x) {
a[j] = y;
cnt[i][x] --, cnt[i][y] ++;
if(!f) bcnt[i][bx] --, bcnt[i][by] ++;
}
}
build(i);
} else {
if(!f) bcnt[i][by] += cnt[i][x], bcnt[i][bx] -= cnt[i][x];
cnt[i][y] += cnt[i][x], cnt[i][x] = 0;
change(i, x, y);
}
}
}
}
for(int i = 2; i <= m; i ++) {
cnt[i][x] += cnt[i - 1][x];
cnt[i][y] += cnt[i - 1][y];
if(!f) bcnt[i][bx] += bcnt[i - 1][bx], bcnt[i][by] += bcnt[i - 1][by];
}
}
int ls[N], lss[N];
void query(int l, int r, int k) {
int bl = bel[l], br = bel[r];
if(bl == br) {
pushdown(bl);
for(int i = l; i <= r; i ++) ls[i] = a[i];
nth_element(ls + l, ls + l + k - 1, ls + r + 1);
printf("%d\n", ls[l + k - 1]);
for(int i = l; i <= r; i ++) ls[i] = 0;
} else {
pushdown(bl), pushdown(br);
for(int i = l; i <= R(bl); i ++) {
ls[a[i]] ++;
lss[bel[a[i]]] ++;
}
for(int i = L(br); i <= r; i ++) {
ls[a[i]] ++;
lss[bel[a[i]]] ++;
}
// printf("** %d %d %d %d %d %d %d\n", l, r, k, bl, br, R(bl), L(br));
// for(int i = 1; i <= n; i ++) printf("%d ", ls[i]); printf("\n");
// for(int i = 1; i <= n; i ++) printf("%d ", lss[i]); printf("\n");
int s = 0, ff = 0;
for(int i = 1; i <= bm; i ++) if(! ff) {
if(s + lss[i] + bcnt[br - 1][i] - bcnt[bl][i] >= k) {
//printf("*%d %d %d\n", i, (bel[i] - 1) * blo + 1, bel[i] * blo);
for(int j = (i - 1) * blo + 1; j <= min(i * blo, lim); j ++) {
if(s + ls[j] + cnt[br - 1][j] - cnt[bl][j] >= k) {
printf("%d\n", j);
ff = 1;
break;
} else s += ls[j] + cnt[br - 1][j] - cnt[bl][j];
}
if(ff) break;
} else s += lss[i] + bcnt[br - 1][i] - bcnt[bl][i];
}
for(int i = l; i <= R(bl); i ++) {
ls[a[i]] = 0;
lss[bel[a[i]]] = 0;
}
for(int i = L(br); i <= r; i ++) {
ls[a[i]] = 0;
lss[bel[a[i]]] = 0;
}
}
}
int main() {
//freopen("a.out","w",stdout);
n = rd(), q = rd();
for(int i = 1; i <= n; i ++) a[i] = rd();
init();
// printf("\n");
// for(int i = 1; i <= n; i ++) printf(" %d ", bel[i]); printf("\n");
// for(int i = 1; i <= n; i ++) printf(" %d ", b[i]); printf("\n");
while(q --) {
int o, l, r, x, y;
o = rd();
if(o == 1) {
l = rd(), r = rd(), x = rd(), y = rd();
chan(l, r, x, y);
} else {
l = rd(), r = rd(), x = rd();
query(l, r, x);
}
}
return 0;
}
/*
10 5
1 2 3 3 5 6 7 8 9 10
2 3 5 2
1 3 7 3 7
1 3 7 7 3
2 3 10 4
2 3 10 3
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!