luogu P4688 [Ynoi2016] 掉进兔子洞
https://www.luogu.com.cn/problem/P4688
思路还是能一眼看出来的,主要是有一些小trick
离散化的时候不要去重(填数的时候往后补就好了)
然后发现空间回炸
把询问分个组就好了
10000一组来做,时间复杂度不变,空间缩小
岂不美哉
具体看代码吧
code:
#include<bits/stdc++.h>
#define N 100005
using namespace std;
struct Q {
int l, r, id;
} q[N << 2];
int bel[N];
int cmp(Q x, Q y) {
if(bel[x.l] != bel[y.l]) return x.l < y.l;
return x.r < y.r;
}
bitset<N> mi[20005], s;
int gs[N], vis[N], a[N], b[N], ans[N];
void add(int x) { x = a[x];
s[x + gs[x]] = 1;//往后填
gs[x] ++;
}
void del(int x) { x = a[x];
gs[x] --;
s[x + gs[x]] = 0;
}
void solve(int m) {
memset(gs, 0, sizeof gs);
for(int i = 0; i <= m; i ++) vis[i] = ans[i] = 0;
int sz = 0;
for(int i = 1; i <= m; i ++)
for(int j = 1; j <= 3; j ++)
sz ++, scanf("%d%d", &q[sz].l, &q[sz].r), q[sz].id = i, ans[i] += q[sz].r - q[sz].l + 1;
sort(q + 1, q + 1 + sz, cmp);
int l = 0, r = -1;
s.reset();
for(int i = 1; i <= sz; i ++) {
while(r < q[i].r) add(++ r);
while(l > q[i].l) add(-- l);
while(r > q[i].r) del(r --);
while(l < q[i].l) del(l ++);
if(vis[q[i].id]) mi[q[i].id] &= s;
else mi[q[i].id] = s;
vis[q[i].id] = 1;
}
for(int i = 1; i <= m; i ++) printf("%d\n", ans[i] - 3 * mi[i].count());
}
int n, m;
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), b[i] = a[i];
sort(b + 1, b + 1 + n);
for(int i = 1; i <= n; i ++) a[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b;
int blo = sqrt(n);
for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / blo + 1;
int mm = 10000;
while(m) {
solve(min(mm, m));//分组做
m -= min(mm, m);
}
return 0;
}
空间开不下可以分组做,记住这个小trick