把边按权值大小排序
然后用LCT按时间维护下最大生成树
就好了
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<stack>
#include<set>
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
int u[N],v[N],w[N];
inline int Min(int a,int b){
return w[a]<w[b]?a:b;
}
struct node{
node *ch[2],*f;
int v,idx; bool rev;
bool isr() { return !f || (f->ch[0]!=this && f->ch[1]!=this); }
bool dir() { return f->ch[1]==this; }
void setc(node *c,int d){ ch[d]=c; if (c) c->f=this; }
void push(){
if (rev) { swap(ch[0],ch[1]); if(ch[0])ch[0]->rev^=1; if(ch[1])ch[1]->rev^=1; rev=0; }
}
void upd(){
v=idx; if(ch[0])v=Min(v,ch[0]->v); if(ch[1])v=Min(v,ch[1]->v);
}
}pool[N];
inline void rot(node *x){
node *p=x->f; bool d=x->dir();
if (!p->isr()) p->f->setc(x,p->dir()); else x->f=p->f;
p->setc(x->ch[d^1],d); x->setc(p,d^1); p->upd();
}
stack<node*> sta;
inline void splay(node *x){
node *q=x; for (;!q->isr();q=q->f) sta.push(q); sta.push(q);
while (!sta.empty()) sta.top()->push(),sta.pop();
while (!x->isr())
if (x->f->isr()) rot(x);
else if (x->dir()==x->f->dir()) rot(x->f),rot(x);
else rot(x),rot(x);
x->upd();
}
inline void expose(node *x){
for (node *q=NULL;x;q=x,x=x->f) splay(x),x->ch[1]=q,x->upd();
}
inline void exert(node *x){ expose(x); splay(x); x->rev^=1; }
inline void link(node *x,node *y) { exert(x); x->f=y; }
inline void cut(node *x,node *y) { exert(y); expose(x); splay(x); x->ch[0]=y->f=NULL; x->upd(); }
node *frt(node *x){ expose(x),splay(x); for (;x->push(),x->ch[0];x=x->ch[0]); return x; }
inline int query(node *x,node *y) { exert(y); expose(x); splay(x); return x->v; }
struct edge{
int u,v,w,idx;
bool operator < (const edge & B) const{
return w<B.w;
}
}ed[N];
set<int> Set;
int n,m;
int al,ar;
int fat[N];
inline int Fat(int u){
return u==fat[u]?u:fat[u]=Fat(fat[u]);
}
inline bool Merge(int x,int y){
x=Fat(x); y=Fat(y); if (x==y) return 0;
fat[x]=y; return 1;
}
int lst[N],pnt;
int Ans=1<<30;
int main(){
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++)
read(ed[i].u),read(ed[i].v),read(ed[i].w),ed[i].idx=i;
sort(ed+1,ed+m+1);
for (int i=1;i<=m;i++)
u[i]=ed[i].u,v[i]=ed[i].v,w[i]=ed[i].w,pool[i].idx=pool[i].v=i;
for (int i=m+1;i<=m+n;i++)
pool[i].idx=pool[i].v=i,w[i]=1<<30;
for (int i=1;i<=m;i++){
int u=::u[i],v=::v[i];
if (frt(pool+m+u)==frt(pool+m+v)){
int t=query(pool+m+u,pool+m+v);
if (w[t]<w[i]){
cut(pool+m+::u[t],pool+t),cut(pool+m+::v[t],pool+t);
Set.erase(t);
link(pool+m+u,pool+i),link(pool+m+v,pool+i);
Set.insert(i);
}
}else
link(pool+m+u,pool+i),link(pool+m+v,pool+i),Set.insert(i);
if (Set.size()==n-1){
int l=*Set.begin(),r=*Set.rbegin();
if (w[r]-w[l]<Ans)
Ans=w[r]-w[l],al=l,ar=r;
}
}
for (int i=1;i<=n;i++) fat[i]=i;
for (int i=al;i<=ar;i++)
if (Merge(ed[i].u,ed[i].v))
lst[++pnt]=ed[i].idx;
sort(lst+1,lst+pnt+1);
for (int i=1;i<=pnt;i++)
printf("%d ",lst[i]);
printf("\n");
return 0;
}
还有浅显易懂的二分答案 然后 cdq分治加并查集维护连通性
三个log 略慢
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
int fat[N],rnk[N];
int Tot;
int pnt,sx[N],sy[N],rx[N];
inline void init(int n){
for (int i=1;i<=n;i++) fat[i]=i,rnk[i]=0; pnt=0; Tot=n;
}
inline int Fat(int u){
return u==fat[u]?u:Fat(fat[u]);
}
inline bool Merge(int x,int y){
x=Fat(x),y=Fat(y); if (x==y) return 0;
if (rnk[x]<rnk[y]) swap(x,y);
sx[++pnt]=x; sy[pnt]=y; rx[pnt]=rnk[x]; Tot--;
fat[y]=x; if (rnk[x]==rnk[y]) rnk[x]++; return 1;
}
inline void Back(int bot){
while (pnt>bot){
fat[sy[pnt]]=sy[pnt];
rnk[sx[pnt]]=rx[pnt];
pnt--; Tot++;
}
}
struct edge{
int u,v,w,idx;
void read(int i) {::read(u); ::read(v); ::read(w); idx=i; }
bool operator < (const edge &B) const{
return w<B.w;
}
}ed[N];
int u[N],v[N],w[N];
struct info{
int i,l,r;
info(int i,int l,int r):i(i),l(l),r(r) { }
};
int End;
inline bool Solve(int l,int r,vector<info> &v0){
int bot=pnt,mid=(l+r)>>1;
vector<info> v1,v2;
for (int i=0;i<(int)v0.size();i++)
if (v0[i].l<=l && r<=v0[i].r)
Merge(u[v0[i].i],v[v0[i].i]);
else{
if (v0[i].l<=mid) v1.pb(v0[i]);
if (v0[i].r>mid) v2.pb(v0[i]);
}
if (l==r) {
if (Tot==1) End=l;
int tmp=Tot;
Back(bot);
return tmp==1;
}
int ret=Solve(l,mid,v1) || Solve(mid+1,r,v2);
Back(bot);
return ret;
}
int n,m;
inline bool check(int x){
init(n);
vector<info> v0;
for (int i=1;i<=m;i++)
v0.pb(info(i,i,upper_bound(w+1,w+m+1,w[i]+x)-w-1));
return Solve(1,m,v0);
}
int lst[N],Pnt;
int main(){
freopen("t.in","r",stdin);
freopen("t1.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++) ed[i].read(i);
sort(ed+1,ed+m+1);
for (int i=1;i<=m;i++) u[i]=ed[i].u,v[i]=ed[i].v,w[i]=ed[i].w;
int L=-1,R=w[m]-w[1]+1,MID;
while (L+1<R)
if (check(MID=(L+R)>>1))
R=MID;
else
L=MID;
int al,ar;
ar=End; al=lower_bound(w+1,w+m+1,w[ar]-R)-w;
init(n);
for (int i=al;i<=ar;i++)
if (Merge(ed[i].u,ed[i].v))
lst[++Pnt]=ed[i].idx;
sort(lst+1,lst+Pnt+1);
for (int i=1;i<=Pnt;i++)
printf("%d ",lst[i]);
printf("\n");
return 0;
}