每日一题 牛客基础 第六场 动态最小生成树 最小生成树 线段树
好妙的一题啊,自己是不太能想出来的,其中有几个点。第一个是,区间查询,那应该想到线段树,线段树的每个区间里面存这个区间的边能构成的最小生成树,当然不一定是一颗完整联通的树。然后就是区间合并的问题了,怎么把两个子区间合并成一个大区间呢,其实就是把两个子区间各自存下来的边放在一起,再跑一遍最小生成树,把边存下来。
在合并的时候有个技巧,因为两个子区间存下来的边都是从小到大排好序的,那大区间把这些边加进来的时候可以用归并排序的方式,设两个指针,每次从左右区间选一个小的边加进来,这样大区间的边排序的复杂度就是On的,之后再用kruskal算法求出最小生成树。
你可能会问,每次更新区间要跑一遍最小生成树,不会超时吗?但是看数据,n<200,所以每个子区间最多存199条边,大区间最多只需要398条边来生成树,所以代价还是不大的。
题目给了5s,我的代码跑了0.95s,时间算是非常充裕的。
#include<bits/stdc++.h>
using namespace std;
int n,m,q;
typedef vector<int> vec;
int dsu[205];
int fnd(int x)
{
if(dsu[x]==x)return x;
return dsu[x]=fnd(dsu[x]);
}
int merg(int x,int y)
{
x=fnd(x),y=fnd(y);
dsu[x]=y;
return x!=y;
}
struct EDGE
{
int a,b,w;
}e[30005];
struct node
{
int l,r,v;
vec ve;
} sgt[120005];
void pushup(int &v,vec &u,vec &a,vec &b)
{
v=0;
for(int i=1;i<205;i++)dsu[i]=i;
int i=0,j=0;
u.clear();
while(i<a.size()||j<b.size())
{
if(i<a.size()&&j<b.size())
{
if(e[a[i]].w<e[b[j]].w)
{
if(merg(e[a[i]].a,e[a[i]].b))
u.push_back(a[i]),v+=e[a[i]].w;
i++;
}
else
{
if(merg(e[b[j]].a,e[b[j]].b))
u.push_back(b[j]),v+=e[b[j]].w;
j++;
}
}
else if(i<a.size())
{
if(merg(e[a[i]].a,e[a[i]].b))
u.push_back(a[i]),v+=e[a[i]].w;
i++;
}
else if(j<b.size())
{
if(merg(e[b[j]].a,e[b[j]].b))
u.push_back(b[j]),v+=e[b[j]].w;
j++;
}
}
}
void iniSgt(int p,int l,int r)
{
sgt[p].l=l;
sgt[p].r=r;
if(l==r)
{
sgt[p].ve.push_back(r);
sgt[p].v=e[r].w;
return;
}
int mid=(l+r)/2;
iniSgt(p*2,l,mid);
iniSgt(p*2+1,mid+1,r);
pushup(sgt[p].v,sgt[p].ve,sgt[p*2].ve,sgt[p*2+1].ve);
}
void modify(int p,int X)
{
int l=sgt[p].l,r=sgt[p].r;
if(l==r&&l==X)
{
sgt[p].v=e[X].w;
return;
}
int mid=(l+r)/2;
if(X<=mid)
modify(p*2,X);
if(X>=mid+1)
modify(p*2+1,X);
pushup(sgt[p].v,sgt[p].ve,sgt[p*2].ve,sgt[p*2+1].ve);
}
int query(int p,int x,int y,vec &u)
{
int l=sgt[p].l,r=sgt[p].r;
if(x<=l&&y>=r)
{
vec tmp=u;
int t=0;
pushup(t,u,tmp,sgt[p].ve);
return t;
}
int mid=(l+r)/2,res=0;
if(x<=mid)
res=query(p*2,x,y,u);
if(y>mid)
res=query(p*2+1,x,y,u);
return res;//用两个儿子更新爸爸
}
int cnt[205];
int main()
{
cin>>n>>m>>q;
for(int i=1;i<=m;i++)
cin>>e[i].a>>e[i].b>>e[i].w;
iniSgt(1,1,m);
while(q--)
{
int opt;cin>>opt;
if(opt==1)
{
int x,y,z,t;cin>>x>>y>>z>>t;
e[x].a=y,e[x].b=z,e[x].w=t;
modify(1,x);
}
else
{
int l,r;cin>>l>>r;
vec t;int tot=0;
int ans=query(1,l,r,t);
if(t.size()==n-1)cout<<ans<<endl;
else cout<<"Impossilbe"<<endl;
}
}
}