• [loj3524]钥匙


    由于到达关系具有传递性,可以考虑不断将若干个可以相互到达的点缩点,并且当两个点只能单向到达时,能到达另一个点的点一定不是最小值

    由此,我们来考虑dfs,即不断从一个节点开始,遍历其可以到达的点,当发现了环即将这些点合并(启发式合并),当发现了已经完全搜过(不在栈中)的点即一定不能作为最小值

    在实现上,有一些困难,注意以下细节:

    1.对每一个点还要维护一个钥匙集合,也参与启发式合并

    2.启发式合并时可能有新的边可以到达,在加入时判定即可

    3.由于要弹出元素,且不像强连通分量一样保证必然弹出,因此建议手动模拟栈来实现

    4.在搜过一条边后将其弹出边集,以避免合并后被其他点重复搜索

    5.判定是否遍历到只能单向到达的点,可以在搜索结束后再判定

      1 #include<bits/stdc++.h>
      2 #include"keys.h"
      3 using namespace std;
      4 #define N 300005
      5 #define vi vector<int>
      6 #define fi first
      7 #define se second
      8 stack<int>st;
      9 set<int>key[N];
     10 set<int>::iterator it1;
     11 vector<int>ans,G0[N];
     12 set<pair<int,int> >G1[N];
     13 set<pair<int,int> >::iterator it2;
     14 int n,m,mn,dfn[N],vis[N],f[N],sz[N];
     15 int find(int k){
     16     if (k==f[k])return k;
     17     return f[k]=find(f[k]);
     18 }
     19 int get_sum(int k){
     20     return key[k].size()+G0[k].size()+G1[k].size();
     21 }
     22 void add(int x,int y,int z){
     23     x=find(x);
     24     if (key[x].find(z)!=key[x].end())G0[x].push_back(y);
     25     else G1[x].insert(make_pair(z,y));
     26 }
     27 void merge(int x,int y){
     28     x=find(x),y=find(y);
     29     if (x==y)return;
     30     if (get_sum(x)<get_sum(y))swap(x,y);
     31     f[y]=x;
     32     sz[x]+=sz[y];
     33     for(it1=key[y].begin();it1!=key[y].end();it1++){
     34         int k=(*it1);
     35         key[x].insert(k);
     36         while (1){
     37             it2=G1[x].lower_bound(make_pair(k,0));
     38             if ((it2==G1[x].end())||((*it2).fi!=k))break;
     39             G0[x].push_back((*it2).se);
     40             G1[x].erase(it2);
     41         }
     42     }
     43     key[y].clear();
     44     for(int i=0;i<G0[y].size();i++)G0[x].push_back(G0[y][i]);
     45     G0[y].clear();
     46     for(it2=G1[y].begin();it2!=G1[y].end();it2++)add(x,(*it2).se,(*it2).fi);
     47     G1[y].clear();
     48 }
     49 void dfs(int k){
     50     st.push(k);
     51     while (!st.empty()){
     52         k=st.top();
     53         dfn[k]=1;
     54         if (G0[k].empty()){
     55             vis[k]=1;
     56             st.pop();
     57             continue;
     58         }
     59         int x=find(G0[k].back());
     60         G0[k].pop_back();
     61         if (!dfn[x]){
     62             st.push(x);
     63             continue;
     64         }
     65         if (vis[x])continue;
     66         while (st.top()!=x){
     67             merge(st.top(),k);
     68             st.pop();
     69         }
     70         merge(st.top(),k);
     71         st.pop();
     72         st.push(find(k));
     73     }
     74 }
     75 void check(int x,int y,int z){
     76     x=find(x),y=find(y);
     77     if (x!=y){
     78         if (key[x].find(z)!=key[x].end())vis[x]=1;
     79         if (key[y].find(z)!=key[y].end())vis[y]=1;
     80     }
     81 }
     82 vi find_reachable(vi r,vi u,vi v,vi c){
     83     n=r.size(),m=u.size();
     84     for(int i=1;i<=n;i++){
     85         f[i]=i,sz[i]=1;
     86         key[i].insert(r[i-1]);
     87     }
     88     for(int i=0;i<m;i++){
     89         u[i]++,v[i]++;
     90         add(u[i],v[i],c[i]);
     91         add(v[i],u[i],c[i]);
     92     }
     93     for(int i=1;i<=n;i++)
     94         if (!dfn[i])dfs(i);
     95     memset(vis,0,sizeof(vis));
     96     for(int i=0;i<m;i++)check(u[i],v[i],c[i]);
     97     mn=0x3f3f3f3f;
     98     for(int i=1;i<=n;i++)
     99         if (!vis[find(i)])mn=min(mn,sz[find(i)]);
    100     for(int i=1;i<=n;i++)
    101         if ((!vis[find(i)])&&(sz[find(i)]==mn))ans.push_back(1);
    102         else ans.push_back(0);
    103     return ans;
    104 }
    View Code
  • 相关阅读:
    2018 ICPC南京网络赛 A An Olympian Math Problem(数论题)
    算法竞赛模板 素数测试(Miller-Rabin测试)
    算法竞赛模板 tarjan算法
    2018 CCPC网络赛 1004 Find Integer(勾股数+费马大定理)
    算法竞赛模板 概率dp
    算法竞赛模板 重载运算符
    算法竞赛模板 矩阵快速幂
    算法竞赛模板 回文素数
    算法竞赛模板 AC自动机
    算法竞赛模板 拓扑排序
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15006186.html
Copyright © 2020-2023  润新知