Minimum spanning tree exercises
CF 891C
The meaning of problems
Given an undirected graph, and the K interrogation, each interrogation given a set of edges, the edge set find whether the edge in the minimum spanning tree in the same side of a
Thinking
- First of all, we should be clear.
- If a right edge is \ (W \) side, the right side is smaller than \ (W \) at the sides are trying to join, the original image is communicated, the edges which will not appear in the \ (the MST \) , the otherwise, it may appear in \ (MST \) in
- And some of the same side of the right side for us
- So, we can consider if there is only one inquiry, we asked the side to go from small to large and heavy, for the current one side is right \ (w \) side, we use the original graph edge weight less than \ (w \) side to build a forest or tree. If the ring appear after while adding that this edge must not put this in the minimum spanning tree, this query is \ (False \)
- For multiple sets of inquiry, we must ensure that every inquiry is a picture of connectivity, it requires disjoint-set to have an undo.
- We can be sorted by the right side, there is this side of the inquiry in order to determine. After the addition is complete ask each side to be withdrawn
- So, disjoint-set to withdraw support, can be combined according to rank
summary
- Disjoint-set by the rank and combined undo
Code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include <utility>
#define M 500005
#define N 100005
using namespace std;
int n,m,k,q,top;
int fa[M],stk[M],s[M],ans[M];
struct node{
int id,from,to,val;
}e[M];
vector<node> a[M];
bool cmp(node a,node b){
return a.val <b.val ;
}
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0',ch=getchar();}
return s*w;
}
int find(int x){
while(x!=fa[x]) x=fa[x];
return x;
}
bool unin(int x,int y){
int fx=find(x),fy=find(y);
if(fx==fy) return 0;
if(s[fx]>s[fy]) swap(fx,fy);
fa[fx]=fy;
s[fy]+=s[fx];
stk[++top]=fx;
return true;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
e[i].from =a,e[i].to =b,e[i].val =c;
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d",&k);
for(int j=1;j<=k;j++){
int x;
scanf("%d",&x);
a[e[x].val].push_back({i,e[x].from,e[x].to,e[x].val});
}
}
sort(e+1,e+m+1,cmp);
for(int i=1;i<=n;i++) fa[i]=i,s[i]=1;
for(int i=1;i<=m;i++){
int val=e[i].val ;
top=0;
for(int j=0;j<a[val].size();j++){
if(ans[a[val][j].id]) continue;
if(j>0&&a[val][j].id!=a[val][j-1].id){
while(top){
int x=stk[top--];
s[fa[x]]-=s[x];
fa[x]=x;
}
}
if(!unin(a[val][j].from,a[val][j].to)) ans[a[val][j].id]=1;
}
while(e[i].val ==val) unin(e[i].from ,e[i].to),i++;
if(e[i].val!=val) i--;
}
for(int i=1;i<=q;i++)
if(ans[i]) printf("NO\n");
else printf("YES\n");
return 0;
}
CF125E
The meaning of problems
- Given \ (N \) points \ (M \) without edges to FIG obtains \ (1 \) dots the degree \ (K \) of the minimum spanning tree
\(N<=5000,M<=10^5\)
Thinking
- We consider the start and again the minimum spanning tree, if the point is 1 degree k, then get an answer directly
- If the degree <k, we can put the right number Collage 1:00 unity even lose \ (x \)
- Conversely, if the degree \ (> k \) , we then add \ (x \)
- So, how much is this x take it right
- Because of \ (X \) values monotonicity
- We can consider half \ (x \)
But there is a problem, different form the minimum spanning tree, that might be the number one point edge weights even the same side. One point we should choose and even \ (k \) that one of the edges, but it is difficult to operate. We several multiple dichotomy is adjusted such that x satisfies the minimum spanning tree edge exactly 1 is selected from the point of attachment.
summary
- For the Minimum Spanning Tree of limitation, two points increment
Bug
- Note that half the time to write \ (l, r \) values
Code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define M 100005
using namespace std;
int n,m,k,res,jus;
int fa[5005],ton[5005];
struct node{
int from,to,id;
double val;
bool tag;
}e[M],oge[M];
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0',ch=getchar();}
return s*w;
}
int find(int x){
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
bool cmp(node a,node b){
if(a.val==b.val) return a.from <b.from ;
return a.val <b.val ;
}
int SPFA(){
int res=0;ton[0]=0;
for(int i=1;i<=n;i++) fa[i]=i;
sort(e+1,e+m+1,cmp);
// for(int i=1;i<=m;i++) cout<<e[i].id<<" ";
// cout<<endl;
for(int i=1;i<=m;i++){
int x=find(e[i].from) ,y=find(e[i].to) ;
if((x==y)||(e[i].from ==1&&res==k)) continue;
fa[x]=y;
if(e[i].from ==1) res++;
ton[++ton[0]]=e[i].id ;
}
// cout<<res<<endl;
return res;
}
bool check(double x){
for(int i=1;i<=m;i++) {
e[i]=oge[i];
if(oge[i].from ==1) {
e[i].val +=x;
// cout<<e[i].id <<" ";
}
}
// cout<<endl;
int now=SPFA();
// cout<<now<<endl;
if(now==k) return 1;
return 0;
}
int main()
{
n=read();m=read();k=read();
for(int i=1;i<=m;i++){
oge[i].id=i,oge[i].from =read(),oge[i].to =read();
scanf("%lf",&oge[i].val);
if(oge[i].from> oge[i].to){
int tep=oge[i].from ;
oge[i].from=oge[i].to ;
oge[i].to =tep;
}
}
sort(oge+1,oge+m+1,cmp);
double l=-10001.0,r=10001.0,ans;
while(l<=r){
double mid=(l+r)/2;
// cerr<<l<<" "<<r<<" "<<mid<<" "<<endl;
if(check(mid)) l=mid+0.01,ans=mid;
else r=mid-0.01;
// if(check(mid)==k) {ans=mid;break;}
// else if(check(mid)<k) r=mid-1;
// else if(check(mid)>k) l=mid+1,ans=mid;
// printf("%d %d %d %d\n",l,mid,r,check(mid));
// cout<<ans<<" "<<check(ans)<<endl;
}
if(!check(ans)||(ton[0]!=n-1)){printf("-1\n");return 0;}
printf("%d\n",n-1);
for(int i=1;i<=ton[0];i++) printf("%d ",ton[i]);
// for(int i=1;i<=m;i++)
// if(e[i].tag){printf("%d ",e[i].id);
// printf("%d %d %d\n",e[i].id,e[i].from ,e[i].to);
// }
return 0;
}
BZOJ 3732 (Kruskal tree reconstruction
The meaning of problems
Given a \ (N \) points \ (M \) without edges to FIG.
There \ (Q \) group query, each interrogation points \ ((s, t) \ ) among all paths which the longest side is the minimum number.
Thinking
- It must be walking on the minimum spanning tree path bottlenecks.
- It can be determined after the minimum spanning tree path with the maximum support to find a tree.
- Traditional practices tree section, can be doubled.
- The use of \ (the Kruskal \) reconstructed tree, the path between two points is the maximum value of the reconstructed tree points \ (the LCA \) .
Kruskal tree reconstruction
- In \ (the Kruskal \) implementation process, when using two sets and check and set (two trees) root, we create a point to the right connecting the two sides of the right-node set as the root size.
- nature:
- Between two points on a minimum spanning tree is a maximum right side tree reconstructed right point LCA
- Reconstruction of a binary tree, points are \ (. 1-2N \) , the number of sides is \ (4N-2 \) , depth \ (n-\)
- The whole tree is a large root heap
Bug
- Reconstruction of the number of sides of the tree should be four times points, twice the number of edges
I opened the small half
summary
\ (kruskal \) reconstruction of the tree must be open enough space
Code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 30005
#define M 30005
using namespace std;
int n,m,k,res,tot;
int head[N],fa[N],f[N][21],a[N],dep[N];
struct node{
int from,to,net,val;
}e[M<<1],mp[M];
void add(int a,int b){
e[++tot].to=b,e[tot].net =head[a],head[a]=tot;
e[++tot].to=a,e[tot].net =head[b],head[b]=tot;
}
bool cmp(node a,node b){
return a.val <b.val ;
}
int find(int x){
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void work(){
for(int i=1;i<2*n;i++) fa[i]=i;
for(int i=1;i<=m;i++){
int u=mp[i].from ,v=mp[i].to ,w=mp[i].val ;
int fu=find(u),fv=find(v);
if(fu==fv) continue;
// cout<<fu<<" "<<fv<<" ";
++res;
fa[fu]=res;
fa[fv]=res;
// cout<<fa[fu]<<" "<<fa[fv]<<endl;
a[res]=w;
add(fu,res);
add(fv,res);
f[fu][0]=res;
f[fv][0]=res;
// cout<<"D"<<endl;
if(res==2*n-1) break;
}
}
void dfs(int x,int last){
for(int i=head[x];i;i=e[i].net){
int to=e[i].to ;
if(to==last) continue;
dep[to]=dep[x]+1;
dfs(to,x);
}
}
void pre(){
for(int j=1;j<=19;j++)
for(int i=1;i<=res;i++) f[i][j]=f[f[i][j-1]][j-1];
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=19;i>=0;i--)
if(dep[f[x][i]]>=dep[y]) x=f[x][i];
if(x==y) return x;
for(int i=19;i>=0;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
mp[i].from=a,mp[i].to=b,mp[i].val =c;
}
sort(mp+1,mp+m+1,cmp);
res=n;
work();
dep[res]=1;
dfs(res,0);
// f[res][0]=res;//<dep[i]<<" "<<f[i][0]<<" "
// for(int i=1;i<=res;i++) cout<<a[i]<<endl;
// cout<<endl;
// cout<<"De"<<endl;
pre();
while(k--){
int u,v;
scanf("%d%d",&u,&v);
// cout<<u<<" "<<v<<" "<<LCA(u,v)<<endl;
printf("%d\n",a[LCA(u,v)]);
}
return 0;
}