题意
给出一个n个点m条边的无向联通图(n,m<=5e5),有q(q<=5e5)个询问
每个询问询问一个边集{Ei},回答这些边能否在同一个最小生成树中
分析
要知道一个性质,就是权值不同的边之间是独立的,即权值为x的所有边的选取不影响权值>x的边的选取
于是我们可以把所有询问离线,按边权排序,对于当前处理的边权,如果有某个询问在其中,那么我们把这些边加进去看有没有环,如果有,那么这个询问就被叉掉了,当然处理完了还要把刚才的操作撤销掉
处理了当前权值x的所有询问,最后别忘了把权值为x的边做kruskal算法加进去
这样时间复杂度是带log的(按秩合并的可撤销并查集的复杂度)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=5e5; 4 int f[maxn+5],sz[maxn+5]; 5 int ans[maxn+5]; 6 struct Edge 7 { 8 int u,v,w; 9 }edge[maxn+5]; 10 vector<int> b[maxn+5]; 11 vector<int> q[maxn+5]; 12 struct question 13 { 14 int id,from,to; 15 }; 16 vector<question> a[maxn+5]; 17 int n,m,Q; 18 bool cmp(const int x,const int y) 19 { 20 return edge[x].w<edge[y].w; 21 } 22 stack<pair<int,int> > s; 23 int find(int x) 24 { 25 if(f[x]==x) return x;else return find(f[x]); 26 } 27 void Union(int x,int y) 28 { 29 if(sz[x]<sz[y]) f[x]=y,sz[y]+=sz[x],s.push(make_pair(x,y)); 30 else f[y]=x,sz[x]+=sz[y],s.push(make_pair(y,x)); 31 } 32 void remove() 33 { 34 pair<int,int> u=s.top(); 35 s.pop(); 36 f[u.first]=u.first; 37 sz[u.second]-=sz[u.first]; 38 } 39 bool check(int id,int from,int to) 40 { 41 bool ans=1; 42 int sum=0; 43 for(int i=from;i<=to;++i) 44 { 45 int p=q[id][i]; 46 int x=find(edge[p].u),y=find(edge[p].v); 47 if(x!=y) Union(x,y),++sum;else ans=0; 48 } 49 for(int i=1;i<=sum;++i) remove(); 50 return ans; 51 } 52 int main() 53 { 54 scanf("%d%d",&n,&m); 55 for(int i=1;i<=m;++i) 56 scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w),b[edge[i].w].push_back(i); 57 scanf("%d",&Q); 58 for(int i=1;i<=Q;++i) 59 { 60 q[i].clear(); 61 int num,x; 62 scanf("%d",&num); 63 while(num--) 64 { 65 scanf("%d",&x); 66 q[i].push_back(x); 67 } 68 sort(q[i].begin(),q[i].end(),cmp); 69 int from=0; 70 for(int j=1;j<q[i].size();++j) 71 if(edge[q[i][j]].w!=edge[q[i][j-1]].w) 72 { 73 a[edge[q[i][j-1]].w].push_back({i,from,j-1}); 74 from=j; 75 } 76 a[edge[q[i][q[i].size()-1]].w].push_back({i,from,q[i].size()-1}); 77 } 78 for(int i=1;i<=n;++i) f[i]=i,sz[i]=1; 79 for(int i=1;i<=maxn;++i) 80 { 81 for(int j=0;j<a[i].size();++j) 82 if(!check(a[i][j].id,a[i][j].from,a[i][j].to)) ans[a[i][j].id]=1; 83 for(int j=0;j<b[i].size();++j) 84 { 85 int p=b[i][j]; 86 int x=find(edge[p].u),y=find(edge[p].v); 87 if(x!=y) Union(x,y); 88 } 89 } 90 for(int i=1;i<=Q;++i) 91 if(ans[i]) printf("NO ");else printf("YES "); 92 return 0; 93 }