题目链接:点击查看

题目大意:给出一张 n 个点 m 条边的无向图,现在需要将这张图转换为有向图,并且使得 k 个可达条件成立,输出一种构造方案

题目分析:如果在无向图中出现环的话,那么在转换为有向图后,环上的点一定是可以使得互相可达的,所以我们考虑 tarjan 边双缩点,将整个图缩成一棵树,在缩边的时候,只需要在 dfs 树上一直加边就可以构造环了

现在只需要考虑缩边后的树边方向即可,对于一个可达条件的限制 ( x , y ) ,设是需要从 x -> y,因为在一棵树上路径唯一,我们先求出 lca = LCA( x , y ) ,维护两个数组 in 和 out ,其意义分别是:

  1. in[ i ] :有 in[ i ] 条边的方向需要从 fa[ i ] -> i
  2. out[ i ] :有 out[ i ] 条边的方向需要从 i -> fa[ i ]

对于一条边 ( x , y ) ,可以用树链剖分,分别维护 x -> lca 和 lca -> y 这两段的边上的 in 数组和 out 数组,最后对于某条边来说,如果 in[ i ] 和 out[ i ] 皆不为 0 的话,那么显然是无解的,否则根据上面的两种情况确定一下

不过马哥有个很棒的想法,就是用树上差分来代替树链剖分,对于一个要求 ( x , y ) 来说,只需要让 out[ x ] ++ , out[ lca ] -- , in[ y ] ++ , in[ lca ] -- ,最后一遍 dfs 统计一下树上前缀和就好了,时空复杂度以及代码难度相对树链剖分来说都优秀太多了

剩下的就是实现了,耐心码就好了,没什么坑点

代码:

#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=1e4+100;const int M=2e5+100;set<pair<int,int>>ans,st;struct Egde
{int to,next;
}edge1[M],edge2[M];int head1[N],head2[N],low[N],dfn[N],c[N],out[N],in[N],num,cnt1,cnt2,dcc,n,m;bool bridge[M],vis[M];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,int in_edge)
{dfn[u]=low[u]=++num;for(int i=head1[u];i!=-1;i=edge1[i].next){int v=edge1[i].to;if(!dfn[v]){tarjan(v,i);low[u]=min(low[u],low[v]);if(low[v]>dfn[u])bridge[i]=bridge[i^1]=true;}else if(i!=(in_edge^1))low[u]=min(low[u],dfn[v]);}
}void dfs(int u)
{c[u]=dcc;for(int i=head1[u];i!=-1;i=edge1[i].next){int v=edge1[i].to;if(bridge[i])continue;if(!vis[i]&&!vis[i^1]){ans.insert(make_pair(u,v));vis[i]=vis[i^1]=true;}if(c[v])continue; dfs(v);}
}void solve()
{for(int i=1;i<=n;i++)//找桥 if(!dfn[i])tarjan(i,0);for(int i=1;i<=n;i++)//缩点 if(!c[i]){dcc++;dfs(i);}
}void build()//缩点+连边
{solve();for(int i=2;i<cnt1;i+=2){int u=edge1[i^1].to;int v=edge1[i].to;if(c[u]==c[v])continue;addedge2(c[u],c[v]);addedge2(c[v],c[u]);}
}int deep[N],dp[N][20],limit;void dfs1(int u,int fa,int dep)//树上倍增
{deep[u]=dep;dp[u][0]=fa;for(int i=1;i<=limit;i++)dp[u][i]=dp[dp[u][i-1]][i-1];for(int i=head2[u];i!=-1;i=edge2[i].next){int v=edge2[i].to;if(v!=fa)dfs1(v,u,dep+1);}
}int LCA(int x,int y)
{if(deep[x]<deep[y])swap(x,y);for(int i=limit;i>=0;i--)if(deep[x]-deep[y]>=(1<<i))x=dp[x][i];if(x==y)return x;for(int i=limit;i>=0;i--)if(dp[x][i]!=dp[y][i]){x=dp[x][i];y=dp[y][i];}return dp[x][0];
}void dfs2(int u,int fa)//统计树上差分的前缀和
{for(int i=head2[u];i!=-1;i=edge2[i].next){int v=edge2[i].to;if(v==fa)continue;dfs2(v,u);in[u]+=in[v];out[u]+=out[v];}
}void init()
{ans.clear();limit=log2(n)+1;cnt1=2;cnt2=num=dcc=0;memset(head2,-1,sizeof(head2));memset(head1,-1,sizeof(head1));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(bridge,false,sizeof(bridge));memset(c,0,sizeof(c));memset(out,false,sizeof(out));memset(in,false,sizeof(in));memset(vis,false,sizeof(vis));
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);scanf("%d%d",&n,&m);init();while(m--){int u,v;scanf("%d%d",&u,&v);addedge1(u,v);addedge1(v,u);}build();dfs1(1,0,0);int x,y;int k;scanf("%d",&k);while(k--){int x,y;scanf("%d%d",&x,&y);if(c[x]==c[y])//属于同一个连通分量 continue;int lca=LCA(c[x],c[y]);//c[x]->c[y]out[c[x]]++;out[lca]--;in[c[y]]++;in[lca]--;}dfs2(1,-1);bool flag=true;for(int i=1;i<=dcc;i++)//枚举每个点与其父节点的关系 {if(out[i]&&in[i]){flag=false;break;}if(out[i])st.insert(make_pair(i,dp[i][0]));elsest.insert(make_pair(dp[i][0],i));}if(!flag)return 0*puts("No");for(int i=2;i<cnt1;i++){int u=edge1[i].to,v=edge1[i^1].to;if(c[u]==c[v])continue;if(st.count(make_pair(c[u],c[v])))ans.insert(make_pair(u,v));}puts("Yes");for(auto it:ans)printf("%d %d\n",it.first,it.second);return 0;
}

中石油训练赛 - One-Way Conveyors(边双缩点+树上差分)相关推荐

  1. 中石油训练赛 - Plan B(点双缩点+树形dp)

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. 中石油训练赛 - Bad Treap(数学)

    题目链接:点击查看 题目大意:给出笛卡尔树的定义,现在要求给出 n 个点对 ( x , sin( x ) ),使得笛卡尔树的高度尽可能大 题目分析:如果想让笛卡尔树的高度尽可能大,令其退化为一条链即可 ...

  9. 中石油训练赛 - High Load Database(二分+记忆化)

    题目链接:点击查看 题目大意:给出一个长度为 n 的数列,再给出 m 次询问,每次询问给出一个阈值 x ,问最少将数列分割成多少段,可以使得每一段的总和都不超过 x,无解的话输出 Impossible ...

最新文章

  1. Yoshua Bengio团队通过在网络「隐藏空间」中使用降噪器以提高深度神经网络的「鲁棒性」
  2. 大会直击|微软亚洲研究院刘铁岩:深度学习成功的秘密
  3. Express框架Restful API Ajax 跨域 开启Cookie支持
  4. 达到年薪 40W 必需掌握的技术
  5. 【今日CV 视觉论文速览】Thu, 21 Feb 2019
  6. Python编程基础15:异常
  7. html生物代码,方舟生存进化全生物代码
  8. ARM嵌入式最小系统
  9. 好玩的黑客游戏(过把黑客的瘾)
  10. 这个开源的去马赛克神器 修复受损漫画无压力
  11. 【BZOJ1061】【NOI2008】志愿者招募 费用流神题、单纯形裸题(代码费用流)
  12. Android使用Socket.IO实现即时通讯
  13. 视频制作和php,【艾奇电子相册视频制作软件和PHP学校网站系统哪个好用】艾奇电子相册视频制作软件和PHP学校网站系统对比-ZOL下载...
  14. 虚拟机中无ens33文件的解决办法
  15. 心情纸条/心动盲盒/交友盲盒
  16. Neos Flow ActionController 返回JSON
  17. MSVCRTD.lib
  18. 12月14日:跟着猫叔写代码api中的增删改查
  19. 更改tkinter的OptionMenu背景颜色和下拉菜单宽度
  20. 客观赋权法的python实现

热门文章

  1. 计算机四级信息安全题,2014年计算机四级考试信息安全工程精选真题
  2. 有哪些非关系型数据库
  3. MySQL高级 - 常用工具 - mysqlshow
  4. Eureka-服务注册
  5. Java领域的对象如何传输-了解序列化的意义
  6. Condition源码分析
  7. SpringMVC拦截器-知识小结
  8. 后台服务系统之什么是dubbo
  9. Lambda表达式有参数有返回值的练习(自定义接口)
  10. 单例设计模式-饿汉式