浅 谈 分 块
【块状链表的超高速实现】
众所周知
- 建立块状链表。 假设我们想从一个数组
a 构造;可以依次提取数组的前B/2 元素当一个vector 添加。可能有用来添加一个哨兵元素在数组尾部。(应用B/2 的原因接下来讲。) - 找到第
k 元素。 这里我们k 从 0 开始标号。我们依次遍历这些vector 。如果当前k 小于当前vector 大小,那么可以直接返回当前vector 的第k 元素。否则,这一个vector 的所有元素都在接下来的vector 的所有元素前面;从k 减除掉当前vector 大小。 - 插入。 首先,我们需要知道插入的位置。为了方便默认是在给定插入位置的前面插入;直接用
vector::insert 。为了保证时间复杂度,如果插入完导致这个vector 大于B ,则在B/2 处分裂这个vector 。具体怎么分裂:- 在块状链表里找到这个
vector 接下来的vector ;在接下来的vector 之前插入一个新建的vector 。 - 这个新建
vector 应该保存刚才插入的vector 的B/2 元素后缀,也就是vector::end()-B/2,vector::end() 这个iterator 区间。可以用这个区间当参数做emplace\_back 。我们用B/2 分裂来平均分裂后的vector 长度,并同时保证没有vector 长度超过B 。这也是为什么我们在上面选取B/2 。 - 建完新的
vector ,再删除这个区间。
- 在块状链表里找到这个
- 删除。 同样找到位置,利用
vector::erase 。如果这个vector 的大小变为零,把这个vector 从块状链表删除。
时间复杂度
以下默认
定理:块状链表总共
引理:找第
引理:插入的时间复杂度是
引理:删除的时间复杂度是
于是整体任何操作的时间复杂度保证为
例题1:数列分块入门 6
题意:在第
模板题。操作和以上描述的一样,还少了一个删除?话说为什么数据随机 关于实现细节,可以外层叫“链表”的东西仍然用
例题2:P4008 [NOI2003] 文本编辑器
题意:维护一个字符串,支持插入一串,删除一串,询问一串。
首先,move prev next 都是同一个操作穿不同的外装,维护一个正整数代表当前指针。
这里,如果按照以上方法暴力一个一个加入一个一个删除,操作复杂度
- 维护: 定义“维护”为保证:
- 当前的块状链表没有一个
vector 长度超过O(B) ; - 当前的块状链表没有一个空
vector 。 - 和上一道题不同,现在可能有至多一个
vector 长度无限,或者会有一个区间空vector ,会给定这个vector 的具体位置或首位置。具体做法:对于情况 1,把这串的结尾O(B) 字符分裂出来,插入到这个vector 后面,继续递归维护当前vector 。对于情况 2,删除这个vector 并且继续递归维护。
- 当前的块状链表没有一个
- 捆绑插入: 可以直接找到对应
vector 插入一大堆,然后调用“维护”。 - 捆绑删除: 稍微复杂点,找到开始删除的地方,然后每次尽量删除可能多的值,知道遍历完或删完,然后调用“维护”。
- 捆绑输出: 找到开始输出位置,和删除一样方法继续遍历。
接下来证明时间复杂度。
定理:对第一情况,“维护”和初始化一个关于维护的
引理:插入时间复杂度是
引理:删除时间复杂度是
引理:输出时间复杂度为
虽然长度能到 2e6,虽然卡满可以调用 3e6 次输出,STL 的常数是超级小。注意这里可以用
Final Boss: P6136 【模板】普通平衡树(数据加强版)
题意:维护一个 order statistic 集合。
首先,我们可以把“无序”变成“有序”:选择维护当前集合的排序顺序。
我们第一需要实现是找到一个元素会在哪里插入来保证有序性。如果一整个块状链表是有序,那么所有内层
插入就直接这样(套普通块状链表插入方法)实现了,删除同理。第
接下来就是
块状链表可以称作“五分钟写完的平衡树”。
习题
- P4278 带插入区间K小值
【奇怪莫队】
众所周知莫队是分块,但是莫队不是数据结构
P1972 [SDOI2009]HH的项链
你真觉得我会讲暴力莫队吗
注意直接 naive 莫队是过不了的。
考虑用
- 散块询问
O(\log^2 n) ,总共有O(q) 个,对时间复杂度贡献O(q\log^2 n) - 单点修改
O(\log n\sqrt n) ,总共有O(q) 个,对时间复杂度贡献O(m\log n\sqrt n) - 块初始化
O(\log n\sqrt n) ,总共有O(\sqrt n) 个,时间复杂度O(n\log n)
炸 出 翔
我们可以离线,然后已经在逐块处理,可以在一个块内两个修改之间的整块询问对
发现单点修改仅仅会影响
于是做到了一个
13 Happy Sugar Life
考虑我们把询问矩形分开来成若干行区间和列区间,怎么计算答案?
(R1C1) | (R1C2) | (R1C3) |
---|---|---|
(R2C1) | (R2C2) | (R2C3) |
(R3C1) | (R3C2) | (R3C3) |
贡献的对可以分为几类。
- 对在一个子矩形内,对每一个矩形预处理答案。
- 对在同一个行区间或者列区间,在这个行区间或者列区间上面求区间逆序对。
- 对在不同的行区间和列区间,可以做一个二维前缀和统计。
注意第一类会在第二类包含,并且第二类会统计第一类两次,所以需要容斥出来。形式化:
如果我们按照树套树的子矩形来维护答案的话,可以做到
接下来讲实现细节:
- 内层树套树需要用动态开点线段树实现。
- 更方便来让外层标号为值域,内层标号为位置。
- 内层的每一个树都会对应一个值域区间。对这个值域区间先建立完动态开点线段树的形态以及子树大小,然后再dfs初始化逆序对个数。后者用归并排序。
- 区间逆序对用常数最小的方法,莫队二次离线。
- 1 贡献直接按照初始化的东西求。
- 2 贡献全部离线求。对外层树套树对应的值域区间放上位置区间的询问;对内层树套树对应的位置区间放上值域区间的询问。
- 3 的贡献维护一个子树大小后缀和数组。
接下来讲卡常方法:
- 减少数组询问次数,也就是对 3 时候不要开二维数组,而滚动的维护一个以为数组。
- 减少访问区间逆序对的常数,扔掉长度为 0 或者 1 的逆序对询问区间。
- 搞评测波动
接下来讲卡内存方法:
发现我们现在内存复杂度是
dfs 到一个外层线段树节点上,建立内层线段树,用完然后把内层线段树的所有关键节点都清零。最重要是现在都不需要动态开点了,大大减少时空常数。最后需要注意我们离线的方法。不应该在每一个线段树节点上方
仍然有继续卡常的余地:
- 整数排序用《P4604 [WC2017]挑战》的基数排序,然后只需要三轮。
- 区间逆序对里的离散化不要用二分,而直接用数组即可,毕竟值域是
O(n) 。不离散化也不行,区间逆序对需要是O(|A|) 才能保证整体时间复杂度。
14 GOSICK
首先,区间满足某条件(
我们需要
这个可以拆成两个部分:
- 计算
\Delta(p,p+1) - 计算
\sum(\Delta(p,i):L\le i\le R)
所以其实
定义:
贡献就等于了:
由于
但是实际上开一个
最终时间复杂度
【例题参考代码】
数列分块入门 6
没封装
#include <bits/stdc++.h>
using namespace std;
#define iter(i, a, b) for(int i=(a); i<(b); i++)
#define rep(i, a) iter(i, 0, (a))
#define rep1(i, a) iter(i, 1, (a)+1)
using vi=vector<int>;
vector<vi> kzlb;
const int th=300;
pair<int, vi::iterator> fin(int kth) {
rep(i, kzlb.size()) {
if(kth < kzlb[i].size()) return {i, kzlb[i].begin()+kth};
kth -= kzlb[i].size();
}
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
int n; cin >> n;
vi ar(n+1);
rep(i, n) cin >> ar[i];
int l=0;
while(l != n+1) {
int r = min(n+1,l+th);
kzlb.emplace_back(ar.begin()+l, ar.begin()+r);
l=r;
}
rep(i, n) {
int o, l, r, c; cin >> o >> l >> r >> c;
if(o == 0) {
l--;
auto v = fin(l);
int i = v.first;
kzlb[i].insert(v.second, r);
if(kzlb[i].size() == 2*th) {
kzlb.emplace(kzlb.begin()+i+1, kzlb[i].begin()+th, kzlb[i].end());
kzlb[i].erase(kzlb[i].begin()+th, kzlb[i].end());
}
} else cout << *fin(r-1).second << endl;
}
return 0;
}
[NOI2003]文本编辑器
#include <bits/stdc++.h>
using namespace std;
#define iter(i, a, b) for(int i=(a); i<(b); i++)
#define rep(i, a) iter(i, 0, (a))
#define rep1(i, a) iter(i, 1, (a)+1)
#define fi first
#define se second
char inpf[1<<23],oupf[1<<23];
char *inp=inpf,*oup=oupf;
string gl() {
string v;
char tmp=*(inp++);
while(tmp == '\n' || tmp == '\r') tmp = *(inp++);
while(tmp != '\n' && tmp != '\r') { v += tmp; tmp = *(inp++); }
return v;
}
vector<string> kzlb;
const int th=3000;
pair<int,int> gt(int idx) {
rep(i, kzlb.size()) {
if(idx < kzlb[i].size()) return {i, idx};
idx -= kzlb[i].size();
}
return {0, 0};
}
void maintain(int idx) {
if(idx == kzlb.size()) return;
if(kzlb[idx].size() == 0) {
kzlb.erase(kzlb.begin()+idx);
maintain(idx);
} else if(kzlb[idx].size() > 2*th) {
kzlb.emplace(kzlb.begin()+idx+1, kzlb[idx].substr(kzlb[idx].size()-th));
kzlb[idx].erase(kzlb[idx].size()-th);
maintain(idx);
}
}
int main() {
fread(inpf, 1, 1<<23, stdin);
int n = stol(gl()), k = 0;
kzlb.push_back("!");
string d, st;
while(n--) {
istringstream com(gl()); com >> d;
if(d == "Insert") {
int n; com >> n;
st = gl();
while(st.size() != n) st += gl();
auto v = gt(k);
kzlb[v.fi].insert(v.se, st);
maintain(v.fi);
}
if(d == "Move") com >> k;
if(d == "Delete") {
int n; com >> n;
auto v = gt(k); int i=v.fi;
while(n) {
int st=v.se, en=min(st+n,(int)kzlb[i].size());
kzlb[i].erase(st, en-st);
n -= en-st;
i++;v.se=0;
}
maintain(v.fi);
}
if(d == "Get") {
int n; com >> n;
auto v = gt(k); int i=v.fi;
while(n) {
int st=v.se, en=min(st+n,(int)kzlb[i].size());
iter(j, st, en) *(oup++) = (kzlb[i][j]);
n -= en-st;
i++;v.se=0;
}
*(oup++) = ('\n');
}
if(d == "Prev") k--;
if(d == "Next") k++;
// for(string i:kzlb) cout << i;
// cout << endl;
}
fwrite(oupf, 1, oup-oupf, stdout);
return 0;
}
普通平衡树 加强版
// writer: w33z8kqrqk8zzzx33
#include <bits/stdc++.h>
using namespace std;
// begin fast read template by CYJian (source: https://www.luogu.com.cn/paste/i11c3ppx)
namespace io {
const int __SIZE = (1 << 21) + 1;
char ibuf[__SIZE], *iS, *iT, obuf[__SIZE], *oS = obuf, *oT = oS + __SIZE - 1, __c, qu[55]; int __f, qr, _eof;
#define Gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, __SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush () { fwrite (obuf, 1, oS - obuf, stdout), oS = obuf; }
inline void gc (char &x) { x = Gc(); }
inline void pc (char x) { *oS ++ = x; if (oS == oT) flush (); }
inline void pstr (const char *s) { int __len = strlen(s); for (__f = 0; __f < __len; ++__f) pc (s[__f]); }
inline void gstr (char *s) { for(__c = Gc(); __c < 32 || __c > 126 || __c == ' ';) __c = Gc();
for(; __c > 31 && __c < 127 && __c != ' '; ++s, __c = Gc()) *s = __c; *s = 0; }
template <class I> inline bool gi (I &x) { _eof = 0;
for (__f = 1, __c = Gc(); (__c < '0' || __c > '9') && !_eof; __c = Gc()) { if (__c == '-') __f = -1; _eof |= __c == EOF; }
for (x = 0; __c <= '9' && __c >= '0' && !_eof; __c = Gc()) x = x * 10 + (__c & 15), _eof |= __c == EOF; x *= __f; return !_eof; }
template <class I> inline void print (I x) { if (!x) pc ('0'); if (x < 0) pc ('-'), x = -x;
while (x) qu[++ qr] = x % 10 + '0', x /= 10; while (qr) pc (qu[qr --]); }
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
} using io::pc; using io::gc; using io::pstr; using io::gstr; using io::gi; using io::print;
// end fast read template by CYJian
#define iter(i, a, b) for(int i=(a); i<(b); i++)
#define rep(i, a) iter(i, 0, a)
#define rep1(i, a) iter(i, 1, (a)+1)
#define log(a) cerr<<"\033[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"\033[0m"<<endl
#define all(a) a.begin(), a.end()
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using ll=long long;
using pii=pair<int, int>;
//#define int ll
const int MOD = 1000000007;
const int sz=1000,th=2*sz;
using vi=vector<int>;
struct Splay {
vector<vi> dt;
Splay(vi q){
sort(all(q));
dt.emplace_back();
rep(i,q.size()){
dt.back().push_back(q[i]);
if(dt.back().size() == sz) dt.emplace_back();
}
if(!dt.back().size())dt.pop_back();
}
int get(int p){
int las=-2e9;
rep(i,dt.size()){
if(las<p&&p<=dt[i].back())return i;
las=dt[i].back();
}
return -1;
}
void ins(int p){
int it=get(p);
dt[it].emplace(lower_bound(all(dt[it]),p),p);
if(dt[it].size()>th){
dt.emplace(dt.begin()+it+1,dt[it].end()-sz,dt[it].end());
dt[it].erase(dt[it].end()-sz,dt[it].end());
}
}
void ers(int p) {
int it=get(p);
dt[it].erase(lower_bound(all(dt[it]),p));
if(!dt[it].size())dt.erase(dt.begin()+it);
}
int kth(int p){
for(vi&v:dt){if(v.size()<=p)p-=v.size();else return v[p];}
}
int clt(int p){
int ans=0;for(vi&v:dt){
if(v.back()<p)ans+=v.size();
else{for(int&i:v)ans+=(i<p);break;}
}
return ans;
}
int pre(int p){
int it=get(p);
auto ps=lower_bound(all(dt[it]),p);
if(ps==dt[it].begin())return dt[it-1].back();
return *prev(ps);
}
int nex(int p){
int it=get(p);
auto ps=upper_bound(all(dt[it]),p);
if(ps==dt[it].end())return dt[it+1].front();
return *ps;
}
};
signed main() {
// ios_base::sync_with_stdio(false); cin.tie(0);
int n=0,m;
gi(n);
gi(m);
vector<int> ar(n);
rep(i, n) gi(ar[i]);
ar.pb(2e9);
Splay sp(ar);
int la = 0; ll sm = 0;
rep1(i, m) {
// cerr << i << ' ';
int op,x;
gi(op), gi(x);
// cin >> op >> x;
x ^= la;
if(op == 1) sp.ins(x);
if(op == 2) sp.ers(x);
if(op == 3) sm ^= (la = (sp.clt(x)+1));
if(op == 4) sm ^= (la = sp.kth(x-1));
if(op == 5) sm ^= (la = sp.pre(x));
if(op == 6) sm ^= (la = sp.nex(x));
// cerr << la << endl;
// sp.dfs(sp.rt); cerr << endl;
// return 0;
}
print(sm);
}
P1972 [SDOI2009]HH的项链
// writer: w33z8kqrqk8zzzx33
#include <bits/stdc++.h>
using namespace std;
// begin fast read template by CYJian (source: https://www.luogu.com.cn/paste/i11c3ppx)
namespace io {
const int __SIZE = (1 << 21) + 1;
char ibuf[__SIZE], *iS, *iT, obuf[__SIZE], *oS = obuf, *oT = oS + __SIZE - 1, __c, qu[55]; int __f, qr, _eof;
#define Gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, __SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush () { fwrite (obuf, 1, oS - obuf, stdout), oS = obuf; }
inline void gc (char &x) { x = Gc(); }
inline void pc (char x) { *oS ++ = x; if (oS == oT) flush (); }
inline void pstr (const char *s) { int __len = strlen(s); for (__f = 0; __f < __len; ++__f) pc (s[__f]); }
inline void gstr (char *s) { for(__c = Gc(); __c < 32 || __c > 126 || __c == ' ';) __c = Gc();
for(; __c > 31 && __c < 127 && __c != ' '; ++s, __c = Gc()) *s = __c; *s = 0; }
template <class I> inline bool gi (I &x) { _eof = 0;
for (__f = 1, __c = Gc(); (__c < '0' || __c > '9') && !_eof; __c = Gc()) { if (__c == '-') __f = -1; _eof |= __c == EOF; }
for (x = 0; __c <= '9' && __c >= '0' && !_eof; __c = Gc()) x = x * 10 + (__c & 15), _eof |= __c == EOF; x *= __f; return !_eof; }
template <class I> inline void print (I x) { if (!x) pc ('0'); if (x < 0) pc ('-'), x = -x;
while (x) qu[++ qr] = x % 10 + '0', x /= 10; while (qr) pc (qu[qr --]); }
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
} using io::pc; using io::gc; using io::pstr; using io::gstr; using io::gi; using io::print;
// end fast read template by CYJian
#define iter(i, a, b) for(int i=(a); i<(b); i++)
#define rep(i, a) iter(i, 0, a)
#define rep1(i, a) iter(i, 1, (a)+1)
#define log(a) cerr<<"\033[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"\033[0m"<<endl
#define all(a) a.begin(), a.end()
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using ll=long long;
using pii=pair<int, int>;
//#define int ll
const int MOD = 1000000007;
int pre[1<<20], nxt[1<<20], ar[1<<20], lc[1<<20], ans[1<<20];
constexpr int bsize = 1024;
struct qry {
int l, r, id;
const bool operator<(const qry& o) const {
if(l/bsize!=o.l/bsize)return l/bsize<o.l/bsize;
return (l/bsize%2) ? (r<o.r) : (r>o.r);
}
} qs[1<<20];
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0);
int n; gi(n);
rep1(i, n) pre[i] = 0, nxt[i] = n+1, gi(ar[i]);
rep1(i, n) {
pre[i] = lc[ar[i]];
nxt[lc[ar[i]]] = i;
lc[ar[i]] = i;
}
int m; gi(m);
rep(i, m) qs[i].id = i, gi(qs[i].l), gi(qs[i].r);
int L = 1, R = 1, s1 = 1, s2 = 0, s3 = 0, s4 = 0;
sort(qs, qs+m);
rep(i, m) {
for(; L-4 > qs[i].l; L-=4) {
s1 += (R < nxt[L-1]);
s2 += (R < nxt[L-2]);
s3 += (R < nxt[L-3]);
s4 += (R < nxt[L-4]);
}
for(; L > qs[i].l; L--)
s1 += (R < nxt[L-1]);
for(; R+4 < qs[i].r; R+=4) {
s1 += (pre[R+1] < L);
s2 += (pre[R+2] < L);
s3 += (pre[R+3] < L);
s4 += (pre[R+4] < L);
}
for(; R < qs[i].r; R++)
s1 += (pre[R+1] < L);
for(; L+4 < qs[i].l; L+=4) {
s1 -= (R < nxt[L]);
s2 -= (R < nxt[L+1]);
s3 -= (R < nxt[L+2]);
s4 -= (R < nxt[L+3]);
}
for(; L < qs[i].l; L++)
s1 -= (R < nxt[L]);
for(; R-4 > qs[i].r; R-=4) {
s1 -= (pre[R] < L);
s2 -= (pre[R-1] < L);
s3 -= (pre[R-2] < L);
s4 -= (pre[R-3] < L);
}
for(; R > qs[i].r; R--)
s1 -= (pre[R] < L);
ans[qs[i].id] = s1 + s2 + s3 + s4;
}
rep(i, m) print(ans[i]), pc('\n');
}
AT1219 歴史の研究
// writer: w33z8kqrqk8zzzx33
#include <bits/stdc++.h>
using namespace std;
// begin fast read template by CYJian (source: https://www.luogu.com.cn/paste/i11c3ppx)
namespace io {
const int __SIZE = (1 << 21) + 1;
char ibuf[__SIZE], *iS, *iT, obuf[__SIZE], *oS = obuf, *oT = oS + __SIZE - 1, __c, qu[55]; int __f, qr, _eof;
#define Gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, __SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush () { fwrite (obuf, 1, oS - obuf, stdout), oS = obuf; }
inline void gc (char &x) { x = Gc(); }
inline void pc (char x) { *oS ++ = x; if (oS == oT) flush (); }
inline void pstr (const char *s) { int __len = strlen(s); for (__f = 0; __f < __len; ++__f) pc (s[__f]); }
inline void gstr (char *s) { for(__c = Gc(); __c < 32 || __c > 126 || __c == ' ';) __c = Gc();
for(; __c > 31 && __c < 127 && __c != ' '; ++s, __c = Gc()) *s = __c; *s = 0; }
template <class I> inline bool gi (I &x) { _eof = 0;
for (__f = 1, __c = Gc(); (__c < '0' || __c > '9') && !_eof; __c = Gc()) { if (__c == '-') __f = -1; _eof |= __c == EOF; }
for (x = 0; __c <= '9' && __c >= '0' && !_eof; __c = Gc()) x = x * 10 + (__c & 15), _eof |= __c == EOF; x *= __f; return !_eof; }
template <class I> inline void print (I x) { if (!x) pc ('0'); if (x < 0) pc ('-'), x = -x;
while (x) qu[++ qr] = x % 10 + '0', x /= 10; while (qr) pc (qu[qr --]); }
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
} using io::pc; using io::gc; using io::pstr; using io::gstr; using io::gi; using io::print;
// end fast read template by CYJian
#define iter(i, a, b) for(int i=(a); i<(b); i++)
#define rep(i, a) iter(i, 0, a)
#define rep1(i, a) iter(i, 1, (a)+1)
#define log(a) cerr<<"\033[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"\033[0m"<<endl
#define all(a) a.begin(), a.end()
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using ll=long long;
using pii=pair<int, int>;
//#define int ll
const int MOD = 1000000007;
int cnt[100005]; ll glbmx=0;
int val[100005];
struct redaction {
int pos, prevcnt; ll prevmx;
}; stack<redaction> re;
void rollback() {
redaction q = re.top(); re.pop();
cnt[q.pos] = q.prevcnt;
glbmx = q.prevmx;
}
constexpr int N=100005;
constexpr int B=300;
int ar[N<<1];
int n;
void ins(int p, bool side) {
int v = ar[p];
re.push({v, cnt[v], glbmx});
if(!(1 <= p <= n)) return;
cnt[v]++; glbmx = max(glbmx, 1ll*val[v]*cnt[v]);
}
ll ans[N];
vector<pair<int,pii>> buccit[100000/B+5];
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0);
map<int,int> lsh;
int q; gi(n), gi(q);
rep1(i, n) {
gi(ar[i]);
if(!lsh.count(ar[i])) {
lsh[ar[i]] = lsh.size()+1;
val[lsh[ar[i]]] = ar[i];
}
ar[i] = lsh[ar[i]];
}
rep(i, q) {
int l, r; gi(l), gi(r);
if((r-l+1)<=B) {
iter(j, l, r+1) ins(j, 1);
ans[i] = glbmx;
while(re.size()) rollback();
} else buccit[r/B].push_back({l, {r, i}});
}
rep(i, n/B+1) {
while(re.size()) rollback();
int cl = i*B, cr = i*B-1;
sort(all(buccit[i]));
reverse(all(buccit[i]));
for(auto q:buccit[i]) {
while(q.fi < cl) ins(--cl, 0);
int ocr = cr;
while(cr < q.se.fi) ins(++cr, 1);
::ans[q.se.se] = glbmx;
// cout << q.se.se << ' ' << i << ' ' << cl << ' ' << cr << ' ' << ca << endl;
while(ocr < cr) rollback(), cr--;
}
}
rep(i, q) print(ans[i]), pc('\n');
}
SP10707 COT2 - Count on a tree II
// writer: w33z8kqrqk8zzzx33
#include <bits/stdc++.h>
using namespace std;
// begin fast read template by CYJian (source: https://www.luogu.com.cn/paste/i11c3ppx)
namespace io {
const int __SIZE = (1 << 21) + 1;
char ibuf[__SIZE], *iS, *iT, obuf[__SIZE], *oS = obuf, *oT = oS + __SIZE - 1, __c, qu[55]; int __f, qr, _eof;
#define Gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, __SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush () { fwrite (obuf, 1, oS - obuf, stdout), oS = obuf; }
inline void gc (char &x) { x = Gc(); }
inline void pc (char x) { *oS ++ = x; if (oS == oT) flush (); }
inline void pstr (const char *s) { int __len = strlen(s); for (__f = 0; __f < __len; ++__f) pc (s[__f]); }
inline void gstr (char *s) { for(__c = Gc(); __c < 32 || __c > 126 || __c == ' ';) __c = Gc();
for(; __c > 31 && __c < 127 && __c != ' '; ++s, __c = Gc()) *s = __c; *s = 0; }
template <class I> inline bool gi (I &x) { _eof = 0;
for (__f = 1, __c = Gc(); (__c < '0' || __c > '9') && !_eof; __c = Gc()) { if (__c == '-') __f = -1; _eof |= __c == EOF; }
for (x = 0; __c <= '9' && __c >= '0' && !_eof; __c = Gc()) x = x * 10 + (__c & 15), _eof |= __c == EOF; x *= __f; return !_eof; }
template <class I> inline void print (I x) { if (!x) pc ('0'); if (x < 0) pc ('-'), x = -x;
while (x) qu[++ qr] = x % 10 + '0', x /= 10; while (qr) pc (qu[qr --]); }
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
} using io::pc; using io::gc; using io::pstr; using io::gstr; using io::gi; using io::print;
// end fast read template by CYJian
#define iter(i, a, b) for(int i=(a); i<(b); i++)
#define rep(i, a) iter(i, 0, a)
#define rep1(i, a) iter(i, 1, (a)+1)
#define log(a) cerr<<"\033[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"\033[0m"<<endl
#define all(a) a.begin(), a.end()
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using ll=long long;
using pii=pair<int, int>;
//#define int ll
const int MOD = 1000000007;
const int B = 316;
int seq[500005];
int fir[500005], sec[500005], clo, clo2;
int bg[500005], en[500005];
int fa[500005][19];
vector<int> elist[500005];
void dfs(int u, int f) {
bg[u] = clo2++;
fir[u] = clo++;
seq[fir[u]]=u;
fa[u][0] = f;
rep1(i, 18) fa[u][i] = fa[fa[u][i-1]][i-1];
for(int v:elist[u]) if(v != f) dfs(v, u);
sec[u] = clo++;
seq[sec[u]]=u;
en[u] = clo2;
}
int lca(int u, int v) {
if(bg[u] <= bg[v] && bg[v] < en[u]) return u;
for(int i=18; i>=0; i--)
if(!(bg[fa[u][i]] <= bg[v] && bg[v] < en[fa[u][i]]))
u = fa[u][i];
return fa[u][0];
}
struct qr {
int l, r, lc, i;
const bool operator<(const qr& o) const {
if(l/B != o.l/B) return l < o.l;
return ((l/B)%2)?(r<o.r):(r>o.r);
}
} qrs[500005];
int res[500005], cnt[500005];
int ar[500005], globans = 0;
bool has[500005];
void tognode(int u) {
if(has[u]) {
cnt[ar[u]]--;
globans -= !cnt[ar[u]];
} else {
globans += !cnt[ar[u]];
cnt[ar[u]]++;
}
has[u] ^= 1;
}
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0);
en[0] = 1e9;
int n, q;
while(cin >> n >> q) {
clo = clo2 = 0;
rep1(i, n) {
elist[i].clear();
fir[i] = sec[i] = 0;
bg[i] = en[i] = 0;
cnt[i] = ar[i] = has[i] = 0;
rep(j, 19) fa[j][i] = 0;
}
rep(i, q+1) {
res[i] = 0;
qrs[i].l = qrs[i].r = qrs[i].lc = 0;
}
map<int,int> lsh;
rep1(i, n) {
cin >> ar[i];
if(!lsh.count(ar[i]))lsh[ar[i]]=lsh.size()+1;
ar[i]=lsh[ar[i]];
}
rep(i, n-1) {
int u, v; cin >> u >> v;
elist[u].pb(v); elist[v].pb(u);
}
dfs(1, 0);
// rep(i, 2*n) cout << seq[i] << " \n"[i==2*n-1];
rep(i, q) {
qrs[i].i = i;
int u, v; cin >> u >> v;
int L = lca(u, v);
if(u != L && v != L) {
qrs[i].lc = L;
if(sec[u] <= fir[v]) qrs[i].l = sec[u], qrs[i].r = fir[v];
else qrs[i].l = sec[v], qrs[i].r = fir[u];
} else {
if(u == L) u = v;
qrs[i].l = fir[L]; qrs[i].r = fir[u];
}
// cout << u << ' ' << v << ' ' << L << endl;
}
sort(qrs, qrs+q);
int cl = 1, cr = 0;
rep(i, q) {
while(cr < qrs[i].r) tognode(seq[++cr]);
while(qrs[i].l < cl) tognode(seq[--cl]);
while(qrs[i].r < cr) tognode(seq[cr--]);
while(cl < qrs[i].l) tognode(seq[cl++]);
res[qrs[i].i] = globans + (qrs[i].lc ? (!cnt[ar[qrs[i].lc]]) : 0);
}
rep(i, q) cout << res[i] << '\n';
}
}
P5071 [Ynoi2015] 此时此刻的光辉
代码仅搬主要部分。
const int MOD = 19260817;
namespace MillerRabin {
int qpow(int b, int e, int m) {
int ans = 1;
while(e) {
if(e & 1) ans = 1ll*ans*b%m;
b = 1ll*b*b%m;
e >>= 1;
}
return ans;
}
bool test(int n) {
if(n<2 || n%6%4 != 1) return (n|1) == 3;
static int ar[4] = {2, 325, 9375, 28178};
int s=__builtin_ctz(n-1); int d=n>>s;
rep(i, 4) {
int k = qpow(ar[i]%n, d, n); int t=s;
while(k!=1 && k!=n-1 && ar[i]%n && t--) k=1ll*k*k%n;
if(t!=s && k!=n-1) return 0;
}
return 1;
}
}
mt19937 rng;
namespace Factor {
set<int> p;
void mxf(int n) {
if(n == 1) return;
if(MillerRabin::test(n)) { p.insert(n); return; }
auto g = [&](int x){ return (1ll*x*x+1)%n; };
int x = 0, y = 1, pd = 2, tk = 0, tmp;
while(++tk % 10 || __gcd(pd, n) == 1) {
if(x == y) x = rng()%n, y = g(x);
if(tmp = 1ll*(max(x, y) - min(x, y))*pd%n) pd = tmp;
x = g(x), y = g(g(y));
}
int d = __gcd(pd, n);
mxf(d), mxf(n/d);
}
}
map<int,int> wkp;
set<int> sm;
int pw[1<<20];
int inv[3<<20];
int a[100005], lef[100005];
int ba[1<<20], ex[1<<20];
const int bs = 316;
struct qr {
int l, r, i;
const bool operator<(const qr& o) const {
if(l/bs != o.l/bs) return l < o.l;
return ((l/bs)%2) ? (r < o.r) : (r > o.r);
}
} qr[100005];
int ans[100005], smp[100005];
int ps[100005];
int th = 88;
inline void add(int id, int& ca) {
int be = lef[id], en = lef[id+1];
iter(p, be, en) ca=1ll*ca*inv[pw[ba[p]]]%MOD*(pw[ba[p]]+=ex[p])%MOD;
}
inline void del(int id, int& ca) {
int be = lef[id], en = lef[id+1];
iter(p, be, en) ca=1ll*ca*inv[pw[ba[p]]]%MOD*(pw[ba[p]]-=ex[p])%MOD;
}
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0);
int n, q; gi(n), gi(q);
inv[0] = inv[1] = 1;
iter(i, 2, n*30+2) inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD;
int cn = 0;
rng = mt19937(108616);
rep1(i, n) gi(a[i]);
rep(i, q) gi(qr[i].l), gi(qr[i].r), qr[i].i = i, ans[i] = 1;
rep1(p, th) {
if(!MillerRabin::test(p)) continue;
rep1(i, n) {
ps[i] = ps[i-1];
while(a[i] % p == 0) a[i] /= p, ps[i]++;
}
rep(i, q) ans[i] = 1ll * ans[i] * (ps[qr[i].r] - ps[qr[i].l-1] + 1) % MOD;
}
rep1(i, n) {
Factor::p.clear(); Factor::mxf(a[i]);
int v = a[i];
lef[i] = cn;
for(int p:Factor::p) {
if(!wkp.count(p)) wkp[p] = wkp.size();
ba[cn] = wkp[p];
pw[ba[cn]] = 1;
while(v % p == 0) v /= p, ex[cn]++;
cn++;
}
}
lef[n+1] = cn;
sort(qr, qr+q);
int ca = 1, l = 1, r = 0;
rep(i, q) {
while(r < qr[i].r) add(++r, ca);
while(qr[i].l < l) add(--l, ca);
while(qr[i].r < r) del(r--, ca);
while(l < qr[i].l) del(l++, ca);
ans[qr[i].i] = 1ll * ans[qr[i].i] * ca % MOD;
}
rep(i, q) print(ans[i]), pc('\n');
}
P5072 [Ynoi2015] 盼君勿忘
代码仅搬主要部分。
FastMod 是一个快速摸工具。
const int bs = 317;
struct q {
int l, r, p, i;
const bool operator<(const q& o) const {
if(l/bs != o.l/bs) return l < o.l;
return ((l/bs)%2) ? (r < o.r) : (r > o.r);
}
} qr[100005];
int ar[100005], re[100005];
uint64_t vv[100100>>6];
template<typename T>
void process(int wds, T func) {
rep(i, wds) {
if(!vv[i]) continue;
uint64_t cp = vv[i];
while(cp) {
int pos = __builtin_ctzll(cp);
func(i*64|pos);
cp ^= (1ull << pos);
}
}
}
ll mt[100005];
int coun[100005];
int lo[bs+1], hi[bs];
#define rem(aede) { mt[coun[aede]] -= aede; vv[coun[aede]>>6] ^= ((mt[coun[aede]]) ? 0 : (1ull<<(coun[aede]&63))); }
#define ic(aede) { vv[coun[aede]>>6] |= (1ull<<(coun[aede]&63)); mt[coun[aede]] += aede; }
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0);
int n, q; gi(n), gi(q);
rep1(i, n) gi(ar[i]);
rep(i, q) gi(qr[i].l), gi(qr[i].r), gi(qr[i].p), qr[i].i = i;
int cl = 1, cr = 0;
sort(qr, qr+q);
mt[0] = 100000ll*100001/2;
vv[0] = 1;
rep(i, q) {
while(cr < qr[i].r) {
int ad = ar[++cr];
rem(ad); coun[ad]++; ic(ad);
}
while(qr[i].l < cl) {
int ad = ar[--cl];
rem(ad); coun[ad]++; ic(ad);
}
while(qr[i].r < cr) {
int re = ar[cr--];
rem(re); coun[re]--; ic(re);
}
while(cl < qr[i].l) {
int re = ar[cl++];
rem(re); coun[re]--; ic(re);
}
int L = cr - cl + 1;
int p = qr[i].p, ans = 0;
lo[0] = 1;
FastMod F(p);
rep1(i, bs) {
lo[i] = lo[i-1]<<1;
lo[i] -= (lo[i] >= p ? p : 0);
}
hi[0] = 1; hi[1] = lo[bs];
iter(i, 2, bs) hi[i] = F.reduce(1ll*hi[1]*hi[i-1]);
process((L>>6)+1, [&](int i){
ans = F.reduce(ans + F.reduce(1ll * F.reduce(mt[i]) * lo[(L-i)%bs]) * hi[(L-i)/bs]);
});
ll v = 100000ll*100001/2;
v %= p; v = v * lo[L%bs] % p * hi[L/bs] % p;
re[qr[i].i] = (v + p - ans) % p;
}
rep(i, q) print(re[i]), pc('\n');
}