Usmjeri(COCI2017.2)题解
题意
给一棵N个节点的树,编号从1到N,再给定m对点(u,v),你要将树上的每条无向边变为有向边,使得给定的点对都满足u能到达v或v能到达u。问有多少种不同的方案,答案对(1e9+7)求余。
1 ≤ N, m≤ 3e5
题解
我们先推一下
若两个点(U,V)中间有这么一条有向路,那么,路径会不会包括 lca(U,V)上面的点呢?
众所周知,这是树,每个点到祖先只有一条路径,一种走法,若上的去,就下不来了,所以答案是否定的。
于是这道题就要用求lca的方法。
在这条有向路径中所有的边肯定都是一个方向吧,那么说来,就是被一条路径涵盖的边,相当于都处于一个集合中,只要其中之一的方向确定,其他边便都推的出来,整个集合就固定只有两种不同的方案了。这个可以用并查集实现。
怎么确定并查集解法呢。
如果lca(u,v)到u是一种方向(两种方向分别是指向根结点或叶子结点),那么lca(u,v)到v肯定是另一种方向(不同于lca(u,v)到u)。也就是说,lca(u,v)到u的路径的一种方向的情况是与lca(u,v)到v的路径的另一种方向的情况相联系(属于同一种情况中,好好揣摩揣摩),简单来说就是要合并集合。
一个更难的问题,怎么确定方向呢?
干脆,不确定方向了,把两种方向的有向边都建立起来!
这样就好办了,向上的边连向上的边,向下的边连向下的边,lca(u,v)到u的向上边集合就和lca(u,v)到v的向下集合合并……
合并到最后,如果,同一条边向上向下的两种情况都在同一个集合中,这意味着什么?——这条边向上可以推出这条边向下,肯定不对啊!这时意味着无解,就直接输出零了。
从上面的推理可以看出,一条向上或向下的路径(边都处于同一种方向)的处理方式都是相同的。因此我们只需要知道哪些边需要处理,向上合并还是向下合并就行,合并左右路径的不同方向直接在u,v两点向上连的边提前合并。
因此,输入每对(u,v)后,在u点和v点标记要向上处理的深度,最后用一遍dfs连边就行。
对于如何计算那个深度,我是老老实实打倍增算的,巨佬们有好方法自己用。
最后的答案等于 2 ^(并查集集合数 / 2),自己思考。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#define max(x,y) ((x) > (y) ? (x) : (y))
#define min(x,y) ((x) < (y) ? (x) : (y))
#define abs(x) ((x) < 0 ? -(x) : (x))
#define LL long long
#define lowbit(x) (-(x) & (x))
using namespace std;
int read() {
int f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
return x * f;
}
struct it{
int v,id;
it(){}
it(int V,int I){v = V;id = I;}
};
LL mod = 1e9 + 7;
LL ans = 1;
int n,m,i,j,s,o,k,cnt;
int l[300005],r[300005];
vector<it> g[300005];
int d[300005];
int fa[600005];
int fat[300005][20];
int fi[300005];
bool vis[600005];
int q[300005];
int find(int x) {//推荐用循环,不用递归
while(x != fa[x]) {
x = fa[x] = fa[fa[x]];
}
return fa[x];
}
void unionSet(int a,int b) {
int u = find(a),v = find(b);
if(u > v)fa[u] = v;
if(u < v)fa[v] = u;
return ;
}
void pdfs(int x) {
vis[x] = 1;
d[x] = d[fat[x][0]] + 1;
for(int i = 1;i <= 19;i ++) {
fat[x][i] = fat[fat[x][i - 1]][i - 1];
}
for(int i = 0;i < g[x].size();i ++) {
if(!vis[g[x][i].v]) {
fat[g[x][i].v][0] = x;
fi[g[x][i].v] = g[x][i].id;
pdfs(g[x][i].v);
}
}
return ;
}
int LCA(int a,int b) {
if(d[a] > d[b]) {
for(int i = 19;i >= 0;i --) {
if(d[fat[a][i]] >= d[b]) a = fat[a][i];
}
}
if(d[a] < d[b]) {
for(int i = 19;i >= 0;i --) {
if(d[fat[b][i]] >= d[a]) b = fat[b][i];
}
}
if(a == b) return a;
for(int i = 19;i >= 0;i --) {
if(fat[a][i] != fat[b][i]) {
a = fat[a][i];
b = fat[b][i];
}
}
return fat[a][0];
}
int dfs(int x,int pe) {
vis[x] = 1;
int de = 0x7f7f7f7f;
for(int i = 0;i < g[x].size();i ++) {
if(g[x][i].v != fat[x][0] && !vis[g[x][i].v]) {
int dde = dfs(g[x][i].v,g[x][i].id);
de = min(de,dde);
if(d[x] > dde) {
unionSet(pe,g[x][i].id);
unionSet(pe + n,g[x][i].id + n);
}
de = min(de,dde);
de = min(de,dde);
de = min(de,dde);
de = min(de,dde);
}
}
de = min(de,q[x]);
return de;
}
int main() {
n = read();m = read();
for(int i = 1;i < n;i ++) {
s = read();o = read();
g[s].push_back(it(o,i));
g[o].push_back(it(s,i));
fa[i] = i;fa[n + i] = n + i;
}
fat[1][0] = 1;
pdfs(1);
memset(q,0x3f,sizeof(q));
for(int i = 1;i <= m;i ++) {
l[i] = read();r[i] = read();
int lca = LCA(l[i],r[i]);
q[l[i]] = min(q[l[i]],d[lca]);
q[r[i]] = min(q[r[i]],d[lca]);
if(lca != l[i] && lca != r[i]) {
unionSet(fi[l[i]],fi[r[i]] + n);
unionSet(fi[l[i]] + n,fi[r[i]]);
}
}
memset(vis,0,sizeof(vis));
dfs(1,0);
bool flag = 1;
for(int i = 1;i < n;i ++) {
if(find(i) == find(i + n)) {
flag = 0;
}
}
if(!flag) {
printf("0\n");
return 0;
}
memset(vis,0,sizeof(vis));
int ce = 0;
for(int i = 1;i < n;i ++) {
if(!vis[find(i)]) {
vis[find(i)] = 1;
ce ++;
}
}
for(int i = n + 1;i < n + n;i ++) {
if(!vis[find(i)]) {
vis[find(i)] = 1;
ce ++;
}
}
ce /= 2;
for(int i = 1;i <= ce;i ++) {
ans = ans * 2 % mod;
}
printf("%lld\n",ans);
return 0;
}
数月之后的下一篇:Codeforces Round #585 (Div. 2) E. Marbles (状压DP),BZOJ大理石(同一道题)题解
Usmjeri(COCI2017.2)题解的更多相关文章
- San(COCI2017.2)题解
题意 一个人为了楼顶的金币要去跳楼,但是不能往更矮的楼上跳. 求在一个长为N的序列中总点权值和大于等于K的不下降序列数. N<=40,K<=4e10 官方题解 折半搜索的经典例子!N在20 ...
- coci2018 题解
plahte 给定一些矩形和一些有颜色的点,求每个矩形上有多少种颜色的点,保证矩形只有包含和不相交两种关系,规模 \(10^5\). 把每个矩形看成一个点,用扫描线建出森林,同时也顺便处理点. 然后做 ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
随机推荐
- Linux文件拷贝脚本
在工作中,我们经常遇到要从Linux服务器拷贝日志至本地或者定期清理日志的需求,在服务器上,大型系统的日志是按模块存储的,这就导致日志的文件目录较多且层级不统一.我们从众多的目录手工筛选要下载或者删除 ...
- 聊聊 C# 方法重载的底层玩法
最近在看 C++ 的方法重载,我就在想 C# 中的重载底层是怎么玩的,很多朋友应该知道 C 是不支持重载的,比如下面的代码就会报错. #include <stdio.h> int say( ...
- 【SpringBoot】快速入门
博客主页:准Java全栈开发工程师 00年出生,即将进入职场闯荡,目标赚钱,可能会有人觉得我格局小.觉得俗,但不得不承认这个世界已经不再是以一条线来分割的平面,而是围绕财富旋转的球面,成为有钱人不是为 ...
- SpringBoot的浅浅配置和小整合
SpringBoot的浅浅配置和小整合 本文如题,就是浅浅记录一下学习的过程中一些过程,比较简单,并没有多少深度.谢谢! SpringBoot创建 从IDEA中新建项目或者模块.注意jdk版本,一般不 ...
- 从零打造一个Web地图引擎
说到地图,大家一定很熟悉,平时应该都使用过百度地图.高德地图.腾讯地图等,如果涉及到地图相关的开发需求,也有很多选择,比如前面的几个地图都会提供一套js API,此外也有一些开源地图框架可以使用,比如 ...
- 在docker中打开redis 客户端 cli
首先交互方式进入redis容器 docker exec -it redis /bin/bash 随后运行客户端 redis-cli
- 项目: ATM+购物车
ATM+购物车 项目文件: 介绍 以下为文件夹层次和内容: readme.md 1. 需求 模拟银行取款 + 购物全过程 1.注册 2.登录 3.提现 4.还款 5.转账 6.查看余额 7.查看购物车 ...
- gpg加解密异常
在本地windows电脑和开发环境(linux) ,都不报错,但是在测试环境(linux) 上报错. 报错信息 org.bouncycastle.openpgp.PGPException: Excep ...
- 【摸鱼神器】UI库秒变低代码工具——表单篇(二)子控件
上一篇介绍了表单控件,这一篇介绍一下表单里面的各种子控件的封装方式. 主要内容 需求分析 子控件的分类 子控件属性的分类 定义 interface. 定义子控件的的 props. 定义 json 文件 ...
- Solution -「构造」专练
记录全思路过程和正解分析.全思路过程很 navie,不过很下饭不是嘛.会持续更新的(应该). 「CF1521E」Nastia and a Beautiful Matrix Thought. 要把所有数 ...