题意:

给出一个无向图,nnn个点,mmm条边,可能有重边与自环,也可能不连通。qqq 组询问,每组询问给出333个点,uuu、vvv、www,问是否存在两条路径不存在公共边,并且一条路径是v→uv\rightarrow uv→u,另一条路径是w→uw\rightarrow uw→u,存在输出YesYesYes,否则输出NoNoNo. (1≤n≤105,0≤m≤2∗105,1≤q≤105)(1\leq n \leq 10^5,0\leq m\leq 2*10^5,1\leq q\leq 10^5)(1≤n≤105,0≤m≤2∗105,1≤q≤105)


思路:

既然是无向图上求两条互不相交的路径,比较直接的想法就是先求出边双连通分量进行缩点,然后在树上进行考虑。

求出边双连通分量之后,假如 uuu、vvv、www 三点在同一个双连通分量中,则答案必定为YesYesYes。若 vvv、www 在同一个双连通分量中,而uuu在另一个双连通分量中,则答案必定为NoNoNo。若vvv或www和uuu在同一个双连通分量中,另一个点不在其中,则答案也为YesYesYes。考虑完了一个和两个双连通分量的情况之后,我们来考虑三个的情况。

假如 uuu、vvv、www 分属于三个不同的双连通分量中,则需要进行分类。YesYesYes 的情况只有两种,第一种情况是vvv和www都在uuu子树中,即lca(v,w)=ulca(v,w) = ulca(v,w)=u即可,如图(1)(1)(1)。第二种情况是vvv、www中有一个在uuu的子树中,另一个则不在。对于这种情况,我们先求出lca(v,w)=ylca(v,w) = ylca(v,w)=y,再求出x1=lca(u,w),x2=lca(u,v)x_1 = lca(u,w),x_2=lca(u,v)x1​=lca(u,w),x2​=lca(u,v),则x1x_1x1​与x2x_2x2​中一定有一个为yyy,另一个为uuu,才能输出YesYesYes,否则输出NoNoNo. 到此,这题分类讨论就结束了。

但是这一题还需要注意一些细节,因为图可能不连通,因此需要预先判断uuu、vvv、www三个点是否连通,如果不连通,直接输出NoNoNo. 还有一个细节,因为图可能是个森林,因此需要对每一个树进行 lcalcalca 处理。


反思:

比赛的时候想法的确是正确的,也考虑到了图不连通这一特殊情况。但是忘记了图不连通时,需要对森林中每一颗树预处理一遍 lcalcalca,导致最终也没有通过此题,实力还是非常有待提升,继续加油!!


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
typedef double db;
const int N = 2*1e5+100;
const int M = 5*1e5+100;
const db EPS = 1e-9;
using namespace std;struct Edge{    int to,next;
}e[M],ec[M];
int n,m,q,head[N],dfn[N],low[N],headc[N],dis[N],d[N],f[N][20],t;
bool bridge[M];
int tot,num,dcc,tc,DD[N];
int c[N];void init(){tot = tc = 1;num = dcc = 0;rep(i,0,n) head[i] = headc[i] = 0;rep(i,0,2*m) bridge[i] = 0;rep(i,0,n) c[i] = dfn[i] = low[i] = 0;rep(i,0,n) dis[i] = d[i] = DD[i] = 0;
}void add(int x,int y){e[++tot].to = y; e[tot].next = head[x]; head[x] = tot;
}void addc(int x,int y)
{ec[++tc].to = y; ec[tc].next = headc[x]; headc[x] = tc;
}void tarjan(int x,int in_edge)
{dfn[x] = low[x] = ++num;for(int i = head[x]; i ; i = e[i].next){int y = e[i].to;if(!dfn[y]){tarjan(y,i);  //传入边(x,y)的序号low[x] = min(low[x],low[y]);if(low[y] > low[x])  //该边连接(x,y),y点无法连接x点上面的点,因此该边是割边bridge[i] = bridge[i^1] = true;}else if(i != (in_edge^1)) //y点所连接的边 不能是(x,y)边的反向边low[x] = min(low[x],dfn[y]);}
}void dfsD(int x,int hp){DD[x] = hp;for(int i = head[x]; i; i = e[i].next){int y = e[i].to;if(DD[y] == 0) dfsD(y,hp);}
}void dfs(int x)    //用于将图划分为多个边双连通分量
{c[x] = dcc;for(int i = head[x]; i ; i = e[i].next){int y = e[i].to;if(c[y] || bridge[i]) continue;  //如果点y已经属于别的强连通分量,或者边i是割边,则continuedfs(y);}
}void bfs(int s)
{queue<int> q;while(q.size()) q.pop();q.push(s); d[s] = 1; dis[s] = 0;  //把1当做树根while(q.size()){int x = q.front(); q.pop();for(int i = headc[x]; i ;i = ec[i].next){int y = ec[i].to;if(d[y]) continue;d[y] = d[x]+1;dis[y] = dis[x]+1; //dist[y]:从1到y的距离f[y][0] = x;  //y走2^0步到达xfor(int j = 1; j <= t;j++)f[y][j] = f[f[y][j-1]][j-1];q.push(y);}}
}int lca(int x,int y)
{if(d[x] > d[y]) swap(x,y);for(int i = t; i >= 0; i--)if(d[f[y][i]] >= d[x]) y = f[y][i];  //往上追溯,直至y和x位于同一深度if(x == y) return x;  //如果已经找到了,就返回xfor(int i = t; i >= 0; i--)if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];  //x和y同时往上走,一直到x和y恰好为lca的子节点return f[x][0];  //x和y共同的根节点就是lca
}int main()
{int _; scanf("%d",&_);while(_--){scanf("%d%d%d",&n,&m,&q);init();rep(i,1,m){int xx,yy; scanf("%d%d",&xx,&yy);add(xx,yy); add(yy,xx);}int ctt = 0;rep(i,1,n)if(!DD[i]) dfsD(i,++ctt);rep(i,1,n)if(!dfn[i]) tarjan(i,0); //将边序号传进去rep(i,1,n)if(!c[i]){ //如果i点未被标记过++dcc;dfs(i);}rep(i,2,tot){int x = e[i^1].to, y = e[i].to; //记录该边连接的两个端点if(c[x] == c[y]) continue; //如果连接的两个点属于同一连通分量,则continueaddc(c[x],c[y]);  //用连通的分量的编号来代表整个连通分量,以此来进行缩点addc(c[y],c[x]);}t = (int)(log(dcc+1)/log(2))+1;rep(i,1,dcc)if(d[i] == 0) bfs(i);rep(i,1,q){int u,v,w; scanf("%d%d%d",&u,&v,&w);if(DD[u] == DD[v] && DD[u] == DD[w]){if(c[u] == c[v] && c[u] == c[w]) printf("Yes\n");else if(c[v] == c[w] && c[v] != c[u]) printf("No\n");else if(c[u] != c[v] && c[u] != c[w] && c[v] != c[w]){int y = lca(c[v],c[w]);if(y == c[u]) printf("Yes\n");else{int x1 = lca(c[v],c[u]);int x2 = lca(c[w],c[u]);if(x1 == y && x2 == c[u]) printf("Yes\n");else if(x2 == y && x1 == c[u]) printf("Yes\n");else printf("No\n");}}else if(c[v] == c[u] && c[w] != c[v]) printf("Yes\n");else if(c[w] == c[u] && c[w] != c[v]) printf("Yes\n");else printf("No\n");}else printf("No\n");}}return 0;
}

由于ZOJ不能交题了,再次给出数据生成代码,以供对拍。(ZOJ现在可以交题了,题目可以在Problem里面找到)

#include <iostream>
#include <cstdlib>
#include <ctime>
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;char tmp[10] = {'I','S','F','A'};
int vis[1000];int main()
{freopen("/Users/gene_liu/Desktop/pai/text.txt","w",stdout);srand(time(0));int n = 1e5, m = 2*1e5, q = 1e5;printf("1\n%d %d %d\n",n,m,q);rep(i,1,m){int x = rand()%n+1, y = rand()%n+1;printf("%d %d\n",x,y);}rep(i,1,q){int u = rand()%n+1, v = rand()%n+1, w = rand()%n+1;printf("%d %d %d\n",u,v,w);}return 0;
}

【ZOJ 4097 The 19th Zhejiang University Programming Contest H】Rescue the Princess【边双连通缩点+LCA】相关推荐

  1. 2019 The 19th Zhejiang University Programming Contest

    感想: 今天三个人的状态比昨天计院校赛的状态要好很多,然而三个人都慢热体质导致签到题wa了很多发.最后虽然跟大家题数一样(6题),然而输在罚时. 只能说,水题还是刷得少,看到签到都没灵感实在不应该. ...

  2. The 19th Zhejiang University Programming Contest Sponsored by TuSimple

    Problem A Thanks, TuSimple! 比赛地址:http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5 ...

  3. ZOJ3865:Superbot(BFS) The 15th Zhejiang University Programming Contest

    一个有几个小坑的bfs 题目很长,但并不复杂,大概总结起来有这么点. 有t组输入 每组输入n, m, p.表示一个n*m的地图,每p秒按键会右移一次(这个等会儿再讲). 然后是地图的输入.其中'@'为 ...

  4. Sichuan University Programming Contest 2018 Preliminary

    嗯为了防止大家AK,所以这次的A题和K题我们就当做不存在好了! 经历了昨天写了两个多小时的博客没保存的心态炸裂,今天终于下了个Markdown.所以我猜这篇的格式应该会更好看一点! 好吧废话不多说 题 ...

  5. [GYM103660] The 19th Zhejiang University City College Programming Contest 浙大城市学院校赛VP/S

    后面俩小时吃饭睡觉去了- A B C D E F G H I J K L AC AC AC 补 补 AC AC AC AC AC – AC GYM103660A.Who is The 19th ZUC ...

  6. Sichuan University Programming Contest 2011 Preliminary(for Non-SCUers) / M A Simple Problem

    返回目录 题目大意: 背景是acm比赛的成绩排名规则,要求输出成绩最好的那个队. 题目类型: 排序题 题目分析: 利用 #include<algorithm>  的sort排序,自定义cm ...

  7. The 2018 JUST Collegiate Programming Contest H题 Cube

    小学数学题 #include<cstdio> #include<cmath> using namespace std; unsigned long long area, ans ...

  8. ZOJ 4097 Rescue the Princess 边双缩点+LCA

    给你一个图和三个点U,V,W  问你是否存在从U到V和从U到W的两条边不相交路径 先边双缩点 再每个连通分量搞LCA 最后LCA判 #include<bits/stdc++.h> usin ...

  9. *【ZOJ - 3703】Happy Programming Contest(带优先级的01背包)

    题干: In Zhejiang University Programming Contest, a team is called "couple team" if it consi ...

  10. 【ZOJ - 3703】Happy Programming Contest(带优先级的01背包,贪心背包)

    题干: In Zhejiang University Programming Contest, a team is called "couple team" if it consi ...

最新文章

  1. nanodet训练voc数据集
  2. wamp配置虚拟主机
  3. 麻烦的.text字段
  4. RobotFramework读取mysql和oracle数据库
  5. java中哈希表怎么表示_java中HashMap概念是什么?怎么存取实现它?
  6. 前端学习(2464):vue中 slot
  7. linux下cabal安装教程,Centos 7 安装shellcheck
  8. idea 热部署_Spring Boot Idea中热部署(自动刷新)
  9. 使用SimpleDateFormat出现时差
  10. Spring Cloud消息驱动整合
  11. Android之输入银行卡号判断属于哪个银行
  12. 【微信小程序开发小白零基础入门】微信小程序文件API【建议收藏】
  13. 2018年将会改变人工智能的5个大数据趋势
  14. 概率论基础 - 6 - 切比雪夫不等式
  15. pandas数据处理
  16. 三分频电路Verilog设计
  17. Cocos2dx之精灵坐标系
  18. zookeeper和kafka的SASL认证以及生产实践
  19. Linux 命令行模式下退出 vim
  20. 小白对于学习对象和类的总结,定义一个圆柱体类Cylinder,并创建相应的对象,然后计算圆柱体的底面积和面积.

热门文章

  1. Java CopyOnWrite容器
  2. centos引导过程中的故障排除
  3. 大型网站的架构设计问题----大型高并发高负载网站的系统架构[转]
  4. hurst指数matlab代码_Matlab 简介
  5. PyTorch - 数据集介绍(mnist、CIFAR10、CIFAR100)
  6. android studio发包,androidstudio使用gradle打包配置详解.pdf
  7. python 读grid 数据_jqGrid获取到python返回的Json数据,未能显示到页面上,为毛???...
  8. android runtime异常,在做android下拉刷新时遇到异常java.lang.RuntimeException: Can't create handle...
  9. 会场安排问题和NYOJ966
  10. vscode 更改中办发文_如何在Visual Studio代码或VSCode中更改集成终端