传送门: https://ac.nowcoder.com/acm/contest/9986/H
这一题大部分人都是暴力Kruskal冲过去的,额,应该是全部,但这显然不是最优解。
题意
题
意
就
像
题
目
一
样
,
动
态
修
改
和
查
找
最
小
生
成
树
。
题意就像题目一样,动态修改和查找最小生成树。
题意就像题目一样,动态修改和查找最小生成树。
两
个
操
作
:
两个操作:
两个操作:
- 修 改 第 x 条 边 的 连 接 点 和 边 权 修改第x条边的连接点和边权 修改第x条边的连接点和边权
- 查 询 [ l , r ] 所 在 边 组 成 的 最 小 生 成 树 大 小 , 有 则 输 出 , 没 有 输 出 i m p o s s i b l e 查询[l,r]所在边组成的最小生成树大小,有则输出,没有输出impossible 查询[l,r]所在边组成的最小生成树大小,有则输出,没有输出impossible
思路
看
到
最
小
生
成
树
,
就
知
道
可
以
用
K
r
u
s
k
a
l
求
解
。
看到最小生成树,就知道可以用Kruskal求解。
看到最小生成树,就知道可以用Kruskal求解。
修
改
还
是
修
改
,
不
过
查
询
的
时
候
就
要
用
一
次
K
r
u
s
k
a
l
,
遇
到
及
其
恶
心
的
数
据
铁
T
。
修改还是修改,不过查询的时候就要用一次Kruskal,遇到及其恶心的数据铁T。
修改还是修改,不过查询的时候就要用一次Kruskal,遇到及其恶心的数据铁T。
因
为
K
r
u
s
k
a
l
的
复
杂
度
是
和
边
数
m
有
关
的
。
因为Kruskal的复杂度是和边数m有关的。
因为Kruskal的复杂度是和边数m有关的。
看 到 n 只 有 200 , m 有 30000 , 所 以 能 不 能 把 复 杂 度 往 n 上 靠 ? 答 案 是 可 以 的 。 看到n只有200,m有30000,所以能不能把复杂度往n上靠?答案是可以的。 看到n只有200,m有30000,所以能不能把复杂度往n上靠?答案是可以的。
区 间 问 题 ? 线 段 树 ! 区间问题?\red{线段树!} 区间问题?线段树!
线 段 树 维 护 什 么 呢 ? 针 对 每 一 个 节 点 , 我 们 维 护 一 个 数 组 , 这 个 数 组 里 保 存 的 是 生 成 树 的 边 的 集 合 。 线段树维护什么呢?针对每一个节点,我们维护一个数组,这个数组里保存的是生成树的边的集合。 线段树维护什么呢?针对每一个节点,我们维护一个数组,这个数组里保存的是生成树的边的集合。
所 以 我 们 建 树 是 b u i l d ( 1 , 1 , m ) , 根 据 边 建 树 , 而 不 是 点 。 所以我们建树是build(1,1,m),根据边建树,而不是点。 所以我们建树是build(1,1,m),根据边建树,而不是点。
每 次 更 新 的 时 候 都 要 重 新 组 织 最 小 生 成 树 并 保 存 , 就 是 代 码 中 的 p u s h _ u p 。 每次更新的时候都要重新组织最小生成树并保存,就是代码中的push\_up。 每次更新的时候都要重新组织最小生成树并保存,就是代码中的push_up。
Code
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef pair<ll, ll> pll;
#define endl "\n"
#define eb emplace_back
#define mem(a, b) memset(a , b , sizeof(a))
const ll INF = 0x3f3f3f3f;
const ll mod = 998244353;
// const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
const double R = 0.57721566490153286060651209;
const int N = 1e5 + 10;
int n, m, q;
struct Edge {
int u, v, w;
}e[N];
#define lc t[u].l
#define rc t[u].r
struct Tree {
int l, r;
int a[505];
}t[N];
int tot = 1;
int f[N];
int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]);
}
void push_up(int s, int u, int v) {
int x = 1, y = 1, z = 1;
for(int i = 1;i <= n; i++) f[i] = i, t[s].a[i] = 0;
while((t[u].a[x] || t[v].a[y]) && z < n) {
if(e[t[u].a[x]].w < e[t[v].a[y]].w) {
int U = find(e[t[u].a[x]].u);
int V = find(e[t[u].a[x]].v);
if(U != V) {
f[U] = V;
t[s].a[z++] = t[u].a[x];
}
x++;
}
else {
int U = find(e[t[v].a[y]].u);
int V = find(e[t[v].a[y]].v);
if(U != V) {
f[U] = V;
t[s].a[z++] = t[v].a[y];
}
y++;
}
}
}
void build(int u, int l, int r) {
if(l == r) {
t[u].a[1] = l;
return ;
}
int mid = (l + r) / 2;
t[u].l = ++tot; t[u].r = ++tot;
build(lc, l, mid);
build(rc, mid + 1, r);
push_up(u, lc, rc);
}
void modify(int u, int l, int r, int p) {
if(l == r) return ;
int mid = (l + r) / 2;
if(p <= mid) modify(lc, l, mid, p);
else modify(rc, mid + 1, r, p);
push_up(u, lc, rc);
}
void query(int u, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) {
push_up(tot + 2, tot + 1, u);
memcpy(t[tot + 1].a, t[tot + 2].a, 4 * (n + 1));
return ;
}
int mid = (l + r) / 2;
if(ql <= mid) query(lc, l, mid, ql, qr);
if(qr > mid) query(rc, mid + 1, r, ql, qr);
}
void solve() {
scanf("%d%d%d",&n,&m,&q);
e[0].w = INF;
for(int i = 1;i <= m; i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
build(1, 1, m);
while(q--) {
int opt; scanf("%d",&opt);
if(opt == 1) {
int x, y, z, w; scanf("%d%d%d%d",&x,&y,&z,&w);
e[x].u = y; e[x].v = z; e[x].w = w;
modify(1, 1, m, x);
}
else {
int l, r; scanf("%d%d",&l,&r);
if(r - l + 1 < n - 1) {
printf("Impossible\n");
continue;
}
for(int i = 1;i <= n; i++) {
t[tot + 2].a[i] = t[tot + 1].a[i] = 0;
}
query(1, 1, m, l, r);
if(!t[tot + 1].a[n - 1]) {
printf("Impossible\n");
}
else {
int ans = 0;
for(int i = 1;i < n; i++) ans += e[t[tot + 1].a[i]].w;
printf("%d\n",ans);
}
}
}
}
signed main() {
ios_base::sync_with_stdio(false);
// cin.tie(nullptr);
// cout.tie(nullptr);
#ifdef FZT_ACM_LOCAL
freopen("../in.txt", "r", stdin);
freopen("../out.txt", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}