zoukankan      html  css  js  c++  java
  • [CF891C] Envy

    给出一个 n 个点 m条边的无向图,每条边有边权,共 Q次询问,每次给出 (k)条边,问这些边能否同时在一棵最小生成树上。

    Solution

    所有最小生成树中某权值的边的数量是一定的

    加完小于某权值的所有边后图的连通性是一样的

    对于每个询问,每种权值分开考虑

    对每个权值,加完小于这条边的权值后的所有边

    然后判断这个权值在缩点后图上是否成环

    因此需要跑一次 Kruskal 并且记录下对于每条边,加完权值小于它的所有边后,其两个端点所在的连通块编号

    这样询问时只需要拿着并查集搞就可以了

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1000005;
    
    struct edge {
        int u,v,w,id,bu,bv;
        bool operator < (const edge &b) const {
            return w < b.w;
        }
    } e[N];
    
    bool cmp(const edge &a, const edge &b) {
        return a.id < b.id;
    }
    
    int n,m,q,t1,t2,t3,f[N];
    
    int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
    void merge(int i,int j) {if(find(i)!=find(j)) f[find(i)]=find(j); }
    
    int solve(vector <edge> v) {
        /*cout<<"solve"<<endl;
        for(int i=0;i<v.size();i++) cout<<v[i].bu<<" "<<v[i].bv<<" "<<v[i].w<<endl;
        cout<<"-----"<<endl;*/
        map<int,int> mp;
        for(int i=0;i<v.size();i++) mp[v[i].bu]++, mp[v[i].bv]++;
        int ind=0;
        for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++)
            it->second = ++ind;
        for(int i=0;i<v.size();i++) v[i].bu=mp[v[i].bu], v[i].bv=mp[v[i].bv];
        for(int i=1;i<=ind;i++) f[i]=i;
        int flag=1;
        for(int i=0;i<v.size();i++) {
            if(find(v[i].bu)==find(v[i].bv)) flag=0;
            merge(v[i].bu,v[i].bv);
        }
        return flag;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) {
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
            e[i].id=i;
        }
        sort(e+1,e+m+1);
        for(int i=1;i<=n;i++) f[i]=i; 
        for(int i=1;i<=m;i++) {
            if(e[i].w != e[i-1].w) {
                int pos=i;
                while(e[pos].w == e[pos+1].w && pos<m) ++pos;
                for(int j=i;j<=pos;j++) e[j].bu=find(e[j].u), e[j].bv=find(e[j].v);
            }
            merge(e[i].u,e[i].v);
        }
        scanf("%d",&q);
        sort(e+1,e+m+1,cmp);
        //for(int i=1;i<=m;i++) cout<<e[i].bu<<" "<<e[i].bv<<endl;
    
        for(int i=1;i<=q;i++) {
            int tot;
            scanf("%d",&tot);
            vector <edge> v;
            for(int j=1;j<=tot;j++) {
                int tmp;
                scanf("%d",&tmp);
                v.push_back(e[tmp]);
            }
            sort(v.begin(),v.end());
            v.push_back((edge){0,0,0});
            int flag = 1;
            for(int j=0;j<tot;j++) {
                int pos=j;
                while(v[j].w == v[j+1].w && pos<tot-1) ++pos;
                vector <edge> vv;
                for(int k=j;k<=pos;k++) vv.push_back(v[k]);
                flag &= solve(vv);
                j=pos;
            }
            if(flag) puts("YES");
            else puts("NO");
        }
    }
    
  • 相关阅读:
    【转】Intellij IDEA常用配置详解
    scala(一)
    scala(三)
    Scrapy学习篇(六)之Selector选择器
    Scrapy学习篇(五)之Spiders
    Scrapy学习篇(四)之数据存储
    Scrapy学习篇(三)之创建项目
    Scrapy学习篇(二)之常用命令行工具
    Scrapy学习篇(一)之框架
    git实现github仓库和本地仓库同步
  • 原文地址:https://www.cnblogs.com/mollnn/p/12318154.html
Copyright © 2011-2022 走看看