树状数组
树状数组是一种支持单点修改和区间查询,代码量小的数据结构。
普通树状数组维护的信息及运算要满足结合律和可拆分,如加法,乘法,异或等
如下示例加法:
int n, c[N];
int lowbit(int x){return x & -x;}
void modify(int x, int val){
for (; x <= n; x += lowbit(x)) c[x] += val;
}
ll query(int x){ //[1, x]
ll res = 0;
for (; x; x -= lowbit(x)) res += c[x];
return res;
}
线段树
struct info{
};
struct tag{
};
info operator+(const info &l, const info &r){
}
info operator+(const info &v, const tag &t){ // 区间修改
}
tag operator+(const tag &t1, const tag &t2){ //懒标记和并
}
struct Node{
tag t;
info val;
} seg[N * 4];
void settag(int id, tag t){
seg[id].val = seg[id].val + t;
seg[id].t = seg[id].t + t;
}
void pushdown(int id){ // 每一步都需要标记下传
if (){ // 标记非空
settag(id * 2, seg[id].t);
settag(id * 2 + 1, seg[id].t);
//初始化标记
}
}
void update(int id){
seg[id].val = seg[id * 2].val + seg[id * 2 + 1].val;
}
void build(int id, int l, int r){
if (l == r)
{
seg[id].val = info();
seg[id].t = tag();
}
else
{
int mid = (l + r) / 2;
build(id * 2, l, mid);
build(id * 2 + 1, mid + 1, r);
update(id);
}
}
info query(int id, int l, int r, int ql, int qr){
if (l == ql && r == qr)
{
return seg[id].val;
}
int mid = (l + r) / 2;
pushdown(id);
if (qr <= mid)
return query(id * 2, l, mid, ql, qr);
else if (ql > mid)
return query(id * 2 + 1, mid + 1, r, ql, qr);
else
return query(id * 2, l, mid, ql, mid) +
query(id * 2 + 1, mid + 1, r, mid + 1, qr);
}
void modify(int id, int l, int r, int ql, int qr, tag t){
if (l == ql && r == qr)
{
settag(id, t);
return;
}
int mid = (l + r) / 2;
pushdown(id);
if (qr <= mid)
modify(id * 2, l, mid, ql, qr, t);
else if (ql > mid)
modify(id * 2 + 1, mid + 1, r, ql, qr, t);
else
{
modify(id * 2, l, mid, ql, mid, t);
modify(id * 2 + 1, mid + 1, r, mid + 1, qr, t);
}
update(id);
}
字典树
注意:01字典树的二维大小只有2!如果习惯开26则极容易被卡RE
int nxt[N][M], cnt = 0;
void solve(){
int n;
cin >> n;
for (int i = 1; i <= n; i ++ ){
string s;
cin >> s;
int len = s.size();
int now = 0;
for (int j = 0; j < len; j ++ ){
int x = s[j] - 'a';
if (!nxt[now][x]){
nxt[now][x] = ++ cnt;
}
now = nxt[now][x];
}
}
}
随机哈希
解决区间匹配问题
std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
using u64 = unsigned long long ;
const int V = 1e6;
u64 val[V + 1];
void solve() {
for (int i = 1; i <= V; i ++ ){
val[i] = rng();
}
}
1.区间各元素的奇偶性问题,与一个值的具体数目无关 -> 异或
pre[i] = pre[i - 1] ^ a;
//判断 pre[--l] = pre[r]
2.区间重排列问题,与一个值的具体数目有关 -> 加法
pre[i] = pre[i] + a;
//判断pa[r] - pa[--l] == pb[r] - pb[--l]
练习:
https://atcoder.jp/contests/abc367/tasks/abc367_f
https://codeforces.com/contest/2014/problem/H