codeforces 892E(离散化+可撤销并查集)

题意

  给出一个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\n");else printf("YES\n");
92     return 0;
93 }
View Code

 

posted @ 2017-11-30 22:49  Chellyutaha  阅读(792)  评论(0编辑  收藏  举报