标签:ver int 题解 SMT HNOI2012 num siz P3224 nnow
前置知识:kruskal 重构树,主席树
来讲一种目前题解区里没有,使用 kruskal 重构树和主席树,且时间复杂度为一个 log 的做法。
题目大意是给定一张点数为 \(n\) ,初始边数为 \(m\) 的无向图,图中每个点有一个权值,然后有 \(q\) 个操作,每个操作可能是询问与点 \(x\) 联通的点中权值第 \(k\) 小的点的编号,也可能是加入一条无向边。
看到这种与联通性相关的题,自然能想到 kruskal 重构树,于是把操作离线,连边操作直接丢给 kruskal 重构树,把其对应点的限制设为时间戳,然后将询问操作也带上时间戳存下来。
这样我们就解决了动态加边的问题,再给 kruskal 重构树加个倍增,我们就可以快速得到一个询问所对应的点集了。
询问的是第 \(k\) 小,于是在 kruskal 重构树上再跑个 dfs 序,弄颗主席树,此题就做完啦 ^_^
时间复杂度:\(O(qlog(n))\)
此外,实现时有个坑点,这张图不一定联通,所以 dfs 时一定要把每个根都跑了。
参考代码:
#include <bits/stdc++.h>
#define rei register int
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 5, M = 1e5 + 5, MAXQ = 3e5 + 5;
int n, m, Q, tot, totq, num;
int val[N * 2], fa[N * 2], f[N * 2][19], lim[N * 2];
int lson[N * 2], rson[N * 2], siz[N * 2];
int id[N * 2], key[N];
struct Segment_Tree {
int tot, ver[N * 2];
struct node {
int cnt, ls, rs;
} T[N * 39];
int build(int l, int r) {
int nnow = ++tot;
if(l == r) return nnow;
int mid = (l + r) >> 1;
T[nnow].ls = build(l, mid);
T[nnow].rs = build(mid + 1, r);
return nnow;
}
int add(int x, int k, int l, int r, int now) {
int nnow = ++tot;
T[nnow] = T[now];
if(l == r) {
T[nnow].cnt += k;
return nnow;
}
int mid = (l + r) >> 1;
int &L = T[nnow].ls, &R = T[nnow].rs;
if(x <= mid) L = add(x, k, l, mid, T[now].ls);
else R = add(x, k, mid + 1, r, T[now].rs);
T[nnow].cnt = T[L].cnt + T[R].cnt;
return nnow;
}
int ask(int k, int l, int r, int now1, int now2) {
if(l == r) {
return key[l];
}
int L1 = T[now1].ls, R1 = T[now1].rs;
int L2 = T[now2].ls, R2 = T[now2].rs;
int mid = (l + r) >> 1;
if(k <= T[L2].cnt - T[L1].cnt) {
return ask(k, l, mid, L1, L2);
} else {
return ask(k - T[L2].cnt + T[L1].cnt, mid + 1, r, R1, R2);
}
}
} SMT;
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void link(int u, int v, int l) {
if(tot == 2 * n - 1) return;
u = find(u), v = find(v);
if(u == v) return;
fa[u] = fa[v] = f[u][0] = f[v][0] = ++tot;
fa[tot] = f[tot][0] = tot;
lim[tot] = l, val[tot] = inf;
lson[tot] = u, rson[tot] = v;
}
struct query {
int x, k, high;
query(int x = 0, int k = 0, int high = 0) {
this->x = x, this->k = k, this->high = high;
}
} q[MAXQ];
void dfs(int x) {
id[x] = ++num, siz[x] = 1;
if(val[x] == inf) SMT.ver[num] = SMT.ver[num - 1];
else key[val[x]] = x, SMT.ver[num] = SMT.add(val[x], 1, 1, n, SMT.ver[num - 1]);
if(lson[x]) dfs(lson[x]), siz[x] += siz[lson[x]];
if(rson[x]) dfs(rson[x]), siz[x] += siz[rson[x]];
}
int solve(query pb) {
int x = pb.x, k = pb.k, high = pb.high;
for(rei i = 17; i >= 0; --i) {
if(lim[f[x][i]] < high) {
x = f[x][i];
}
}
int l = SMT.ver[id[x] - 1], r = SMT.ver[id[x] + siz[x] - 1];
if(k > SMT.T[r].cnt - SMT.T[l].cnt) return -1;
return SMT.ask(k, 1, n, l, r);
}
int main() {
ios::sync_with_stdio(false), cin.tie(NULL);
cin >> n >> m;
tot = n;
for(rei i = 1; i <= n; ++i) {
cin >> val[i];
fa[i] = f[i][0] = i;
}
for(rei i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
link(u, v, 0);
}
cin >> Q;
for(rei i = 1; i <= Q; ++i) {
char op; int x, y;
cin >> op >> x >> y;
if(op == 'B') {
link(x, y, i);
} else {
q[++totq] = query(x, y, i);
}
}
for(rei j = 1; j <= 17; ++j) {
for(rei i = 1; i <= tot; ++i) {
f[i][j] = f[f[i][j - 1]][j - 1];
}
}
SMT.ver[0] = SMT.build(1, n);
for(rei i = 1; i <= tot; ++i) {
if(fa[i] == i) dfs(i);
}
for(rei i = 1; i <= totq; ++i) {
cout << solve(q[i]) << "\n";
}
return 0;
}
无耻求波赞 QAQ
标签:ver,int,题解,SMT,HNOI2012,num,siz,P3224,nnow 来源: https://www.cnblogs.com/Szzkp/p/15135119.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。