P5313 [Ynoi2011] WBLT 题解
看到值域比较,又支持离线,可以想到莫队和桶。
考虑先将桶按
当
但是发现当
现在考虑
由于
这时就只需在
这一部分的时间复杂度为
时间复杂度:
代码:
const int N = 1e5 + 10, V = 1e5 + 1, MOD = 63, W = 64, bit = 6;
int n, m, len, cq, nowb;
int a[N], cnt[N], ans[N];
ull filter[W];
struct que {
int l, r, b, id;
} q[N];
bool cmp(que a, que b) {
int x = a.l / len, y = b.l / len;
if (x == y) {
if (x & 1) return a.r < b.r;
return a.r > b.r;
}
return a.l < b.l;
}
vector<que> qb[W];
struct bitsett {
int siz;
vector<ull> v;
void reset() { for (int i = 0; i <= siz; i++) v[i] = 0; }
void set() { for (int i = 0; i <= siz; i++) v[i] = ~0ull; }
void set1(int x) { v[x >> bit] |= (1ull << (x & MOD)); }
void set0(int x) { v[x >> bit] &= (~(1ull << (x & MOD))); }
void flip() { for (int i = 0; i <= siz; i++) v[i] = ~v[i]; }
void operator &= (const bitsett &a) { for (int i = 0; i <= siz; i++) v[i] &= a.v[i]; }
int mex() { for (int i = 0; ; i++) if (~v[i]) return i << bit | __builtin_ctzll(~v[i]); }
void init(int x) {
v.resize((x >> bit) + 2);
siz = x >> bit;
reset();
}
bool any() {
for (int i = 0; i <= siz; i++) if (v[i]) return 1;
return 0;
}
};
bitsett cur, res, bl[1605], blb[W + 5];
void split(int len) {
for (int i = 0; i <= V / len + 2; i++) bl[i].init(len);
int ned = bl[0].siz, bg = 0, np = 0, num = 0;
for (int i = 0; i <= cur.siz; i++)
if (np == ned) {
if (bg + (len & MOD) <= MOD) {
bl[num].v[np] = (cur.v[i] & (filter[bg + (len & MOD) - 1] - (bg ? filter[bg - 1] : 0))) >> bg;
i--;
}
else if (i != cur.siz) {
bl[num].v[np] = (cur.v[i] >> bg) | ((cur.v[i + 1] & filter[bg + (len & MOD) - MOD]) << (W - bg));
} else
bl[num].v[np] = (cur.v[i] >> bg);
bg = (bg + (len & MOD)) & MOD, np = 0, num++;
} else {
if (bg == 0) bl[num].v[np] = cur.v[i];
else if (i != cur.siz) bl[num].v[np] = (cur.v[i] >> bg) | ((cur.v[i + 1] & filter[bg - 1]) << (W - bg));
else bl[num].v[np] = cur.v[i] >> bg;
np++;
}
}
void add1(int x) {
cnt[x]++;
if (cnt[x] == 1) cur.set1(x);
}
void del1(int x) {
cnt[x]--;
if (cnt[x] == 0) cur.set0(x);
}
void add2(int x) {
cnt[x]++;
if (cnt[x] == 1) blb[x % nowb].set1(x / nowb);
}
void del2(int x) {
cnt[x]--;
if (cnt[x] == 0) blb[x % nowb].set0(x / nowb);
}
int main() {
filter[0] = 1;
for (int i = 1; i < W; i++) filter[i] = filter[i - 1] + (1ull << i);
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
cin >> m;
for (int i = 1, l, r, b; i <= m; i++) {
cin >> l >> r >> b;
if (b > 63) q[++cq] = (que){l, r, b, i};
else qb[b].pb((que){l, r, 0, i});
}
len = n / sqrt(cq) + 1;
sort(q + 1, q + cq + 1, cmp);
cur.init(V);
for (int i = 1, l = 1, r = 0; i <= cq; i++) {
while (l > q[i].l) add1(a[--l]);
while (r < q[i].r) add1(a[++r]);
while (l < q[i].l) del1(a[l++]);
while (r > q[i].r) del1(a[r--]);
split(q[i].b);
res.init(q[i].b);
res.flip();
for (int j = 0; ; j++) {
res &= bl[j];
if (!res.any()) {
ans[q[i].id] = j;
break;
}
}
}
int mxb = 63;
for (int i = 1; i <= mxb; i++) {
if (qb[i].size() == 0) continue;
memset(cnt, 0, sizeof(cnt));
nowb = i;
len = n / sqrt(qb[i].size()) + 1;
sort(qb[i].begin(), qb[i].end(), cmp);
for (int j = 0; j < i; j++) blb[j].init(V / i + 1);
for (int j = 0, l = 1, r = 0; j < (int)(qb[i].size()); j++) {
while (l > qb[i][j].l) add2(a[--l]);
while (r < qb[i][j].r) add2(a[++r]);
while (l < qb[i][j].l) del2(a[l++]);
while (r > qb[i][j].r) del2(a[r--]);
for (int k = 0; k < i; k++)
ans[qb[i][j].id] = max(ans[qb[i][j].id], blb[k].mex());
}
}
for (int i = 1; i <= m; i++) cout << ans[i] << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现