题解 给国与地震
先来口胡一个场上没写完的做法:
考虑根号分治,以 \(\sqrt m\) 为界
一个暴力是合并时枚举两端点连通块的所有出边
但是度数很大的端点肯定不能直接枚举
那就根号分治,对度数 \(>\sqrt m\) 的连通块开 \(n\) 个优先队列
第 \(i\) 个按 \(s\) 升序存与点 \(i\) 的连边
然后对每个大点再开一个 set 存这个连通块每个优先队列中 \(s_i-siz_v\) 最小的边
合并两个优先队列是 \(O(\min\{siz\}\log n)\) 的
那么合并两个(大)连通块是 \(O(n\sqrt m+\min\{\deg\}\log n)\) 的
合并一大一小两个连通块的时候暴力并进来
因为是在合并连通块,所以对度数套类似启发式合并的复杂度证明可得均摊 \(m\log^2 n\)
合并两个小连通块也是暴力合并边(可能导致其变为一个大连通块)
这些合并导致的 \(siz\) 变化也是可以维护的
大连通块 \(siz\) 的变化直接打标记
小连通块 \(siz\) 变化在所有与之相邻的大连通块对应的优先队列上打标记
虽然可能导致 set 的插入,但仍可以依靠每条边最多产生一次影响均摊下去
所以总复杂度是 \(O(n\sqrt m+m\log^2n)\) 的
空间会很卡,\(\tt priority\_queue\) 可能需要在第一次有值的时候再申请
然后听说有人写 \(O(n\sqrt m\log n)\) 跑过去了,最大的点 200 ms
感觉亏死了 /kk
然后正解:
还是从上面那个暴力入手
考虑这样一个性质:若一条边还需要 \(s_i\),则若两端点的变化量都 \(<\frac{s_i}{2}\),则此边一定不合法,不必 check
那么用 set 启发式合并维护边集,按还需要的 \(s_i\) 排序
若一次合并导致的变化量为 \(k\),只考虑 \(k\geqslant\frac{s_i}{2}\) 的出边,然后更新其临界值
发现每次更新一条边都会使其临界值减半,所以每条边最多更新 \(O(\log n)\) 次
复杂度 \(O((n+m)\log^2 n)\)
然后加反向边的时候忘记把 it->to
改成 u
调了一个小时
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
ll a[N];
int deg[N];
struct edge{int fir, sec, val;}e[N<<1];
namespace force{
ll siz[N];
bool del[N];
int dsu[N], sta[N], top;
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void uni(int s, int t) {if ((s=find(s))!=(t=find(t))) siz[dsu[s]=t]+=siz[s];}
void solve() {
for (int i=1; i<=n; ++i) dsu[i]=i, siz[i]=a[i];
jump: ;
for (int i=1; i<=m; ++i) if (!del[i]) {
if (find(e[i].fir)==find(e[i].sec)) del[i]=1;
else {
if (e[i].val<=siz[find(e[i].fir)]+siz[find(e[i].sec)]) {
del[sta[++top]=i]=1;
uni(e[i].fir, e[i].sec);
goto jump;
}
}
}
printf("%d\n", top);
for (int i=1; i<=top; ++i) printf("%d%c", sta[i], " \n"[i==top]);
}
}
// namespace task1{
// ll siz[N];
// int dsu[N], sta[N], top;
// int id[N], val[N], sqr, tot;
// vector<pair<int, int>> to[N];
// priority_queue<int, vector<int>, greater<int>> que;
// struct point{
// int id;
// bool vis[100005];
// set<pair<int, int>> s;
// struct cmp{inline bool operator () (int a, int b) {return val[a]<val[b];}};
// priority_queue<int, vector<int>, cmp> *q[100005];
// inline void push(int pos, int id) {
// if (!q[pos]) q[pos]=new priority_queue<int, vector<int>, cmp>;
// q[pos]->push(id);
// }
// void build() {
// for (int i=1; i<=n; ++i) if (q[i]&&q[i]->size())
// s.insert({val[q[i]->top()]-siz[i], i});
// }
// void check() {
// while (s.size() && siz[id]>=s.begin()->fir) {
// int v=s.begin()->sec;
// s.erase(s.begin());
// while (q[v]->size() && siz[id]+siz[v]>=val[q[v]->top()])
// que.push(q[v]->top()), q[v]->pop();
// if (q[v]->size()) s.insert()
// }
// }
// }p[250];
// inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
// inline void uni(int s, int t) {if ((s=find(s))!=(t=find(t))) siz[dsu[s]=t]+=siz[s];}
// void solve() {
// cout<<double(sizeof(p))/1000/1000<<endl;
// sqr=sqrt(m); // 记得调成 800+
// for (int i=1; i<=m; ++i) val[i]=e[i].val;
// for (int i=1; i<=m; ++i) to[e[i].fir].pb({e[i].sec, i}), to[e[i].sec].pb({e[i].fir, i});
// for (int i=1; i<=n; ++i) if (to[i].size()>sqr) {
// id[i]=++tot;
// for (auto& it:to[i]) p[tot].push(it.fir, val[it.sec]);
// p[tot].build();
// }
// }
// }
namespace task1{
ll siz[N];
int sta[N], top;
set<pair<int, int>> s;
priority_queue<int, vector<int>, greater<int>> q;
void solve() {
for (int i=1; i<=n; ++i) siz[i]=a[i];
for (int i=1; i<=m; ++i) {
int u=e[i].fir, v=e[i].sec;
if (u!=1) swap(u, v), swap(e[i].fir, e[i].sec);
s.insert({e[i].val-siz[v], i});
}
while (1) {
while (s.size() && siz[1]>=s.begin()->fir) {
q.push(s.begin()->sec);
s.erase(s.begin());
}
if (q.size()) sta[++top]=q.top(), siz[1]+=siz[e[q.top()].sec], q.pop();
else break;
}
printf("%d\n", top);
for (int i=1; i<=top; ++i) printf("%d%c", sta[i], " \n"[i==top]);
}
}
namespace task2{
ll siz[N], val[N];
int dsu[N], sta[N], top;
vector<pair<int, int>> to[N];
priority_queue<int, vector<int>, greater<int>> q;
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void uni(int s, int t) {if ((s=find(s))!=(t=find(t))) siz[dsu[s]=t]+=siz[s];}
void solve() {
for (int i=1; i<=n; ++i) dsu[i]=i, siz[i]=a[i];
for (int i=1; i<=m; ++i) {
val[i]=e[i].val;
to[e[i].fir].pb({e[i].sec, i});
to[e[i].sec].pb({e[i].fir, i});
}
for (int i=1; i<=n; ++i) {
for (int j=0; j<to[i].size(); ++j) if (siz[i]+siz[to[i][j].fir]>=val[to[i][j].sec]) {
q.push(to[i][j].sec);
swap(to[i][j], to[i][to[i].size()-1]);
to[i].pop_back();
--j;
}
}
int now=0;
while (1) {
// cout<<"i: "<<++now<<endl;
while (q.size() && find(e[q.top()].fir)==find(e[q.top()].sec)) q.pop();
if (!q.size()) break;
sta[++top]=q.top();
int u=find(e[q.top()].fir), v=find(e[q.top()].sec);
if (to[u].size()<to[v].size()) swap(to[u], to[v]);
for (auto& it:to[v]) to[u].pb(it);
uni(v, u);
// cout<<"uv: "<<u<<' '<<v<<endl;
for (int j=0; j<to[u].size(); ++j)
if (siz[u]+siz[find(to[u][j].fir)]>=val[to[u][j].sec]) {
// cout<<siz[u]<<' '<<siz[find(to[u][j].fir)]<<' '<<val[to[u][j].sec]<<' '<<to[u][j].sec<<endl;
q.push(to[u][j].sec);
swap(to[u][j], to[u][to[u].size()-1]);
to[u].pop_back();
--j;
}
// else cout<<"fail: "<<siz[u]<<' '<<siz[find(to[u][j].fir)]<<' '<<val[to[u][j].sec]<<endl;
}
printf("%d\n", top);
for (int i=1; i<=top; ++i) printf("%d%c", sta[i], " \n"[i==top]);
}
}
namespace task{
bool del[N];
ll siz[N], val[N];
int dsu[N], lim[N], sta[N], top;
struct edge{ll val; int to, id, s;};
inline bool operator < (edge a, edge b) {return a.val==b.val?a.id<b.id:a.val<b.val;}
set<edge> out[N];
vector<edge> tem;
priority_queue<int, vector<int>, greater<int>> q;
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void uni(int s, int t) {if ((s=find(s))!=(t=find(t))) siz[dsu[s]=t]+=siz[s];}
void solve() {
for (int i=1; i<=n; ++i) dsu[i]=i, siz[i]=a[i];
for (int i=1; i<=m; ++i) {
if (siz[e[i].fir]+siz[e[i].sec]>=e[i].val) q.push(i);
else {
// cout<<"init_edge: "<<e[i].fir<<' '<<e[i].sec<<endl;
out[e[i].fir].insert({siz[e[i].fir]+(e[i].val-siz[e[i].fir]-siz[e[i].sec])/2, e[i].sec, i, e[i].val});
out[e[i].sec].insert({siz[e[i].sec]+(e[i].val-siz[e[i].fir]-siz[e[i].sec])/2, e[i].fir, i, e[i].val});
}
}
int now=0;
while (1) {
// cout<<"i: "<<++now<<endl;
// cout<<"siz: "; for (int i=1; i<=n; ++i) cout<<siz[i]<<' '; cout<<endl;
while (q.size() && find(e[q.top()].fir)==find(e[q.top()].sec)) q.pop();
if (!q.size()) break;
sta[++top]=q.top();
int u=find(e[q.top()].fir), v=find(e[q.top()].sec);
// cout<<"uv: "<<u<<' '<<v<<endl;
// cout<<"siz_uv: "<<siz[u]<<' '<<siz[v]<<endl;
// cout<<"deg: "<<out[u].size()<<' '<<out[v].size()<<endl;
tem.clear();
// cout<<"out of u"<<endl;
for (auto it=out[u].begin(); it!=out[u].end(); it=out[u].erase(it)) {
if (del[it->id]) continue;
if (it->val<=siz[u]+siz[v]) {
// cout<<"edge: ("<<u<<','<<find(it->to)<<") val="<<it->val<<" siz_u+v="<<siz[u]+siz[v]<<" all siz="<<siz[u]+siz[v]+siz[find(it->to)]<<" s="<<it->s<<" id="<<it->id<<endl;
if (siz[u]+siz[v]+siz[find(it->to)]>=it->s) q.push(it->id), del[it->id]=1;
else {
tem.pb({siz[u]+siz[v]+(it->s-siz[u]-siz[v]-siz[find(it->to)])/2, it->to, it->id, it->s});
if (find(it->to)!=u) out[find(it->to)].insert({siz[find(it->to)]+(it->s-siz[u]-siz[v]-siz[find(it->to)])/2, u, it->id, it->s});
}
}
else break;
}
// cout<<"out of v"<<endl;
for (auto it=out[v].begin(); it!=out[v].end(); it=out[v].erase(it)) {
if (del[it->id]) continue;
if (it->val<=siz[u]+siz[v]) {
// cout<<"edge: ("<<v<<','<<find(it->to)<<") val="<<it->val<<" siz_u+v="<<siz[u]+siz[v]<<" all siz="<<siz[u]+siz[v]+siz[find(it->to)]<<" s="<<it->s<<" id="<<it->id<<endl;
if (siz[u]+siz[v]+siz[find(it->to)]>=it->s) q.push(it->id), del[it->id]=1;
else {
tem.pb({siz[u]+siz[v]+(it->s-siz[u]-siz[v]-siz[find(it->to)])/2, it->to, it->id, it->s});
if (find(it->to)!=v) out[find(it->to)].insert({siz[find(it->to)]+(it->s-siz[u]-siz[v]-siz[find(it->to)])/2, v, it->id, it->s});
}
}
else break;
}
if (out[u].size()<out[v].size()) swap(out[u], out[v]);
for (auto& it:out[v]) out[u].insert(it);
for (auto& it:tem) out[u].insert(it);
uni(v, u);
}
printf("%d\n", top);
for (int i=1; i<=top; ++i) printf("%d%c", sta[i], " \n"[i==top]);
}
}
signed main()
{
freopen("earthquake.in", "r", stdin);
freopen("earthquake.out", "w", stdout);
n=read(); m=read();
for (int i=1; i<=n; ++i) a[i]=read();
for (int i=1; i<=m; ++i) {
e[i].fir=read(), e[i].sec=read(), e[i].val=read();
++deg[e[i].fir], ++deg[e[i].sec];
}
// force::solve();
// task2::solve();
// task1::solve();
// if (n<=5000) force::solve();
// else if (m==n-1 && deg[1]==m) task1::solve();
// else task2::solve();
task::solve();
return 0;
}