• 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
    ");else printf("YES
    ");
    92     return 0;
    93 }
    View Code
  • 相关阅读:
    [洛谷P1886]滑动窗口 (单调队列)(线段树)
    树状数组详细解析
    离散化
    kettle使用总结(一)
    springBoot开发的web项目打war包部署到已有的tomcat容器中
    集群时钟同步
    linux服务器安装nginx
    Tomcat学习之体系架构
    码云新建仓库上传项目
    linux系统安装mysql yum方式
  • 原文地址:https://www.cnblogs.com/wmrv587/p/7932321.html
Copyright © 2020-2023  润新知