题目大意:给出一张 n 个点 m 条边的无向连通图,现在有某些点被标记了,问能否通过删除某个未被标记的点,使得删除该点后的数个互不相交的连通块中,至少存在一个联通块中不含有被标记的点

题目分析:首先不难看出,被删掉的点一定是割点,所以我们可以直接用 tarjan 求出割点,然后点双缩一下点,将整个图缩成一棵树,在树上dp即可,dp 的话对于点 u 而言,只需要检查一下其所有子树,以及其父节点上面的那棵子树中,是否存在着不含有标记点的子树即可

代码:

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;const int M=1e6+100;struct Egde
{int to,next;
}edge1[M],edge2[M];int head1[N],head2[N],low[N],dfn[N],c[N],Stack[N],new_id[N],dp[N],num,cnt,cnt1,cnt2,tot,root,top,n,m,b;bool cut[N],ban[N];vector<int>dcc[N];vector<int>ans;map<int,int>mp;void addedge1(int u,int v)
{edge1[cnt1].to=v;edge1[cnt1].next=head1[u];head1[u]=cnt1++;
}void addedge2(int u,int v)
{edge2[cnt2].to=v;edge2[cnt2].next=head2[u];head2[u]=cnt2++;
}void tarjan(int u)
{dfn[u]=low[u]=++num;Stack[++top]=u;if(u==root&&head1[u]==-1){dcc[++cnt].push_back(u);return;}int flag=0;for(int i=head1[u];i!=-1;i=edge1[i].next){int v=edge1[i].to;if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]){flag++;if(u!=root||flag>1)cut[u]=true;cnt++;int x;do{x=Stack[top--];dcc[cnt].push_back(x);}while(x!=v);dcc[cnt].push_back(u);}}elselow[u]=min(low[u],dfn[v]);}
}void solve()
{for(int i=1;i<=n;i++)//找割点+缩点 if(!dfn[i]){root=i;tarjan(i);}
}void build()//缩点+连边
{solve();num=cnt;for(int i=1;i<=n;i++)if(cut[i]){new_id[i]=++num;mp[num]=i;}for(int i=1;i<=cnt;i++)for(int j=0;j<dcc[i].size();j++){int x=dcc[i][j];if(cut[x]){addedge2(i,new_id[x]);addedge2(new_id[x],i);}elsec[x]=i;}
}void dfs(int u,int fa)
{bool flag=false;for(int i=head2[u];i!=-1;i=edge2[i].next){int v=edge2[i].to;if(v==fa)continue;dfs(v,u);if(!dp[v])flag=true;dp[u]+=dp[v];}if(mp.count(u)&&!ban[mp[u]]&&(flag||dp[u]==b))ans.push_back(mp[u]);
}void init()
{for(int i=0;i<N;i++)dcc[i].clear();cnt=cnt2=cnt1=num=tot=top=0;memset(head2,-1,sizeof(head2));memset(head1,-1,sizeof(head1));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(cut,false,sizeof(cut));memset(c,0,sizeof(c));memset(Stack,0,sizeof(Stack));memset(new_id,0,sizeof(new_id));memset(dp,0,sizeof(dp));memset(ban,false,sizeof(ban));mp.clear();ans.clear();
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);init();scanf("%d%d%d",&n,&m,&b);while(m--){int u,v;scanf("%d%d",&u,&v);addedge1(u,v);addedge1(v,u);}build();for(int i=1;i<=b;i++){int x;scanf("%d",&x);ban[x]=true;if(cut[x])dp[new_id[x]]++;elsedp[c[x]]++;}dfs(1,-1);sort(ans.begin(),ans.end());printf("%d\n",ans.size());for(int num:ans)printf("%d ",num);return 0;
}

中石油训练赛 - Plan B(点双缩点+树形dp)相关推荐

  1. 中石油训练赛 - One-Way Conveyors(边双缩点+树上差分)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边的无向图,现在需要将这张图转换为有向图,并且使得 k 个可达条件成立,输出一种构造方案 题目分析:如果在无向图中出现环的话,那么在转换为有向图 ...

  2. 石油大 Contest1777 - 2019年第二阶段我要变强个人训练赛第九场 I 热狗树(树形dp)

    题目描述 "我是番茄酱!" "我是黄芥末酱!" "合在一起就是--美式热狗上加的,那个!" 热狗树上的每个节点都涂有番茄酱或者黄芥末酱中的一 ...

  3. CodeForces - 1220E Tourism(边双缩点+树形dp)

    题目链接:点击查看 题目大意:给出一个由n个点和m条边构成的无向图,每个点都有一个权值,现在给出起点st,问从起点出发,如何规划路线可以使得途径的权值最大,唯一的约束是一条边不能连续经过,比如当前从u ...

  4. 中石油训练赛 - Trading Cards(最大权闭合子图)

    题目大意:给出 n 个卡片,可以自由买卖,且价格都是相同的,再给出 m 个集合,如果已经得到了其中一个集合中的卡片,那么可以获得该集合的收益,问如何操作可以使得收益最大化 题目分析:最大权闭合子图的模 ...

  5. 中石油训练赛 - Watch Later(状压dp)

    题目链接:点击查看 题目大意: 给出一个长度为 n 的字符串,字符串中共有 k 种不同的字符,现在问删除掉所有字符的最小操作数,对于每种字符需要确定一个先后顺序,每次需要删除掉当前所有的这种字符才能去 ...

  6. 中石油训练赛 - Swapping Places(字典序最小的拓扑排序)

    题目链接:点击查看 题目大意:给出 s 个字符串表示种类,再给出 m 个朋友关系,表示两个种类的动物是朋友,现在给出一个长度为 n 的种类排列,规定相邻两个是朋友的种类的动物可以交换位置,问如何操作, ...

  7. 中石油训练赛 - Gone Fishing(固定大小的圆可以覆盖最多的点)

    题目大意:在二维平面中给出 n 个点,再给出一个固定大小的圆,问如何放置这个圆可以使其覆盖最多的点 题目分析:首先不难想到一种 n^3 的做法,就是两层循环去枚举两个点,因为两个不同的点就可以确定下来 ...

  8. 中石油训练赛 - Russian Dolls on the Christmas Tree(树上启发式合并/主席树)

    题目链接:点击查看 题目大意:给出一棵 n 个节点的树,以点 1 为根,现在对于每个节点作为根的子树求解:子树中有多少个编号不相交的连续子段,如:1 2 4 5 7,共有三个连续的段,分别为 [ 1 ...

  9. 中石油训练赛 - Check List(线段树维护偏序问题)

    题目大意:给出 n 个点,需要计算出满足下列条件的三元对 ( i , j , k ) 的数量: x[ i ] < x[ j ] < x[ k ] y[ k ] > y[ i ] &g ...

最新文章

  1. 关系管理系统:js代码生成select的出生日期
  2. 栈区和堆区内存分配区别
  3. UIGestureRecognizer学习笔记
  4. Docker通过Cgroup 资源配置
  5. 电热水器和插座之间的相亲故事
  6. 软件测试工程师-数据库
  7. 不同版本的nutz与log4j2的集成方法
  8. [源码和报告分享]基于Java的局域网聊天工具
  9. 日期 日历 时区 地区 格式化 API 案例 MD
  10. 分布式数据库中间件 TDDL 学习笔记
  11. 一键生成合成微信好友墙
  12. java+ElementUI前后端分离旅游项目第二天 旅游管理和自由行
  13. 蚂蚁金服 RPC 框架 Sofa-Bolt 结构分析
  14. 数据库系统—数据查询
  15. 【Java设计模式】责任链模式
  16. 提高睡眠质量的好物有哪些?五款助眠好物推荐
  17. 腾讯云学生服务器官网地址-腾讯云学生服务器如何购买
  18. 人生的意义是通过努力活得更好
  19. 168.Vue.js智能扫码点餐系统(二)【搭建Vue开发环境】2019.03.18
  20. cpu 占用过高排查

热门文章

  1. iis8.5 php mysql_Win2012 R2 IIS8.5+PHP(FastCGI)+MySQL运行环境搭建教程
  2. html5怎么设置drop,HTML5 拖放(Drag 和 Drop)
  3. NIO和BIO如何影响应用程序的设计-设置处理线程数
  4. 分布式MQ消息存储选择
  5. 经典的X/OpenDTP事务模型
  6. 练习_用if语句实现考试成绩划分
  7. 单继承-问题的抛出-单纯封装可能会出现重复的代码
  8. 在consumer中调用provider服务
  9. 使用网络存储SAN和NAS
  10. 适配器模式源码解析(jdk+spring+springjpa+springmvc)