您的位置:首页 > 理论基础 > 数据结构算法

自备ACM模板-数据结构篇

2020-08-02 16:11 711 查看

ST表

// 求区间最值 洛谷 P3865
#include<bits/stdc++.h>
using namespace std;
int n, k, num[100005];
int ma[100005][25];		// n*logn
void pre(){
for(int i = 1; i <= n; i++)
ma[i][0] = num[i];
int s = 2, s2;
for(int j = 1; s <= n; j++, s <<= 1){
s2 = s;
for(int i = 1; s2 <= n; i++, s2++)
ma[i][j] = max(ma[i][j - 1], ma[i + (s>>1)][j - 1]);
}
}

int qerry(int l, int r){
int k = trunc(log2(r-l+1));	// floor
return max(ma[l][k], ma[r - (1 << k) + 1][k]);
}
// 精髓就是这个区间查询,按区间长度找到对应层级

int main(){
int q;
cin >> n >> q;
for(int i = 1; i <= n; i++)
cin >> num[i];
pre();
int l, r;
for(int i = 1; i <= q; i++){
cin >> l >> r;
cout << qerry(l,r)) << endl;
}
return 0;
}

// ST表还可以通过时间戳找LCA

主席树

// 找区间内第k小(就是升序第k个的意思) 洛谷 P3834
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define maxn 200005
struct node{
int l, r, sum;
}t[maxn*21];
int cnt;
LL a[maxn], b[maxn];
int root[maxn];

void update(int l, int r, int &x, int y, int pos){
x = ++cnt;
t[x] = t[y];
t[x].sum++;
if(l == r) return ;
int m = (l + r) >> 1;
if(pos <= m) update(l, m, t[x].l, t[y].l, pos);
else       	update(m + 1, r, t[x].r, t[y].r, pos);
}

LL query(int l, int r, int x, int y, int k){
if(l == r) return b[l];
int m = (l + r) >> 1;
int s = t[t[y].l].sum - t[t[x].l].sum;
if(k <= s) return query(l, m, t[x].l, t[y].l, k);
else     return query(m + 1, r, t[x].r, t[y].r, k - s);
}

int main(){
int tol, n, m, i, l, r, k;
cin >> n >> m;
for(i=1;i<=n;i++){
cin >> a[i];
b[i] = a[i];
}
sort(b + 1, b + n + 1);
for(i = 1; i <= n; i++)
a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
for(i = 0; i < n; i++) update(1, n, root[i + 1], root[i], a[i + 1]);
for(i = 1; i <= m; i++)
cin >> l >> r >> k;
cout << query(1,n,root[l-1],root[r],k)) << endl;
return 0;
}

树链剖分

// 更新任意两点到LCA的权值,求任意两点到LCA的权值和
// 更新以任意点为根节点的子树的权值,求以任意点为根节点的子树的权值和
// 洛谷 P3384
#include<bits/stdc++.h>
using namespace std;
#define maxn 200010
struct node{
int x, next;
}tree[maxn << 1];
int head[maxn], son[maxn], fa[maxn], dep[maxn], top[maxn];
int id[maxn], tv[maxn], v[maxn], t[maxn<<2], lazy[maxn<<2], size[maxn], cnt, tla, mmod;
void add(int x,int y){
tree[++cnt].x = y;
tree[cnt].next = head[x];
head[x] = cnt;
}
void pushup(int rt){t[rt] = (t[rt<<1] + t[rt<<1|1]) % mmod;}
void build(int l, int r, int rt){
if(l == r) t[rt] = tv[l] % mmod;
else{
int m = (l + r)>>1;
build(l, m, rt<<1);
build(m + 1, r, rt<<1|1);
pushup(rt);
}
}
void pushdown(int rt, int lenl, int lenr){
if(lazy[rt]){
int r1 = rt<<1, r2 = rt<<1|1;
lazy[r1] = (lazy[r1] + lazy[rt]) % mmod;
lazy[r2] = (lazy[r2] + lazy[rt]) % mmod;
t[r1] = (t[r1] + lenl*lazy[rt]) % mmod;
t[r2] = (t[r2] + lenr*lazy[rt]) % mmod;
lazy[rt]=0;
}
}

void update(int L, int R, int k, int l, int r, int rt){
if(L <= l && r <= R){
lazy[rt] = (lazy[rt] + k) % mmod;
t[rt] = (t[rt] + k*(r-l+1)) % mmod;
return;
}
int m = (l+r)>>1;
pushdown(rt, m - l + 1, r - m);
if(L <= m) update(L, R, k, l, m, rt<<1);
if(R > m) update(L, R, k, m + 1, r, rt<<1|1);
pushup(rt);
}

int query(int L, int R, int l, int r, int rt){
if(L <= l && r <= R)
return t[rt] % mmod;
int m = (l + r)>>1;
pushdown(rt, m - l + 1, r - m);
int ans = 0;
if(L <= m) ans += query(L, R, l, m, rt<<1);
if(R > m) ans += query(L, R, m + 1, r, rt<<1|1);
return ans % mmod;
}

void dfs1(int x, int f, int d){
fa[x] = f;
dep[x] = d;
size[x] = 1;
int mmax = -1;
for(int y = head[x]; ~y; y = tree[y].next){
int k = tree[y].x;
if(k == f) continue;
dfs1(k, x, d + 1);
size[x] += size[k];
if(size[k] > mmax){
mmax = size[k];
son[x] = k;
}
}
}

void dfs2(int x, int topf){
top[x] = topf;
id[x] = ++tla;
tv[tla] = v[x];
if(!son[x]) return;
dfs2(son[x], topf);
for(int y = head[x]; ~y; y = tree[y].next){
int k = tree[y].x;
if(k == fa[x] || k == son[x]) continue;
dfs2(k, k);
}
}

void uprange(int x, int y, int z){
z %= mmod;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
update(id[top[x]], id[x], z, 1, tla, 1);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
update(id[x], id[y], z, 1, tla, 1);
}

int qrange(int x, int y){
int ans = 0;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ans=(ans + query(id[top[x]], id[x], 1, tla, 1)) % mmod;
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
return (ans + query(id[x], id[y], 1, tla, 1)) % mmod;
}

void upson(int x, int z){
z %= mmod;
update(id[x], id[x] + size[x] - 1, z, 1, tla, 1);
}

int qson(int x){
return query(id[x], id[x] + size[x] - 1, 1, tla, 1);
}
int main(){
int i, n, root, m, x, y, z, flag;
cin >> n >> m >> root >> mmod;
for(i = 1; i <= n; i++)
cin >> v[i];
memset(head, -1, sizeof(head));
for(i = 1; i < n; i++){
cin >> x >> y;
add(x, y),add(y, x);
}
dfs1(root, 0, 1);
dfs2(root, root);
build(1, tla, 1);
for(i = 1; i <= m; i++){
cin >> flag;
if(flag == 1){
cin >> x >> y >> z;
uprange(x, y, z);
}else if(flag == 2){
cin >> x >> y;
cout << qrange(x,y) << endl;
}else if(flag == 3){
cin >> x >> z;
upson(x, z);
}else{
cin >> x;
cout << qson(x) << endl;
}
}
return 0;}

// 树链剖分就是将叶子到子树的根节点的沿途结点这条链,维护成线段树。
//再将子数结点作为叶子,重复此操作。
//最后等于将树分割为若干条链,这样可以通过线段树维护区间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: