BZOJ3772 精神污染 【主席树 + dfs序】
题目
兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是集经济和文化于一体的一大地区,是日本西部门户,海陆空交通设施发达。濑户内海沿岸气候温暖,多晴天,有日本少见的贸易良港神户港所在的神户市和曾是豪族城邑“城下町”的姬路市等大城市,还有以疗养地而闻名的六甲山地等。
兵库县官方也大力发展旅游,为了方便,他们在县内的N个旅游景点上建立了n-1条观光道,构成了一棵图论中的树。同时他们推出了M条观光线路,每条线路由两个节点x和y指定,经过的旅游景点就是树上x到y的唯一路径上的点。保证一条路径只出现一次。
你和你的朋友打算前往兵库县旅游,但旅行社还没有告知你们最终选择的观光线路是哪一条(假设是线路A)。这时候你得到了一个消息:在兵库北有一群丧心病狂的香菜蜜,他们已经选定了一条观光线路(假设是线路B),对这条路线上的所有景点都释放了【精神污染】。这个计划还有可能影响其他的线路,比如有四个景点1-2-3-4,而【精神污染】的路径是1-4,那么1-3,2-4,1-2等路径也被视为被完全污染了。
现在你想知道的是,假设随便选择两条不同的路径A和B,存在一条路径使得如果这条路径被污染,另一条路径也被污染的概率。换句话说,一条路径被另一条路径包含的概率。
输入格式
第一行两个整数N,M
接下来N-1行,每行两个数a,b,表示A和B之间有一条观光道。
接下来M行,每行两个数x,y,表示一条旅游线路。
输出格式
所求的概率,以最简分数形式输出。
输入样例
5 3
1 2
2 3
3 4
2 5
3 5
2 5
1 4
输出样例
1/3
样例解释
可以选择的路径对有(1,2),(1,3),(2,3),只有路径1完全覆盖路径2。
提示
100%的数据满足:N,M<=100000
题解
真是精神污染= =
我们求出有多少对路径存在包含关系即可
对于路径A,如果路径B的左右端点都在A的路径上,那么A包含B
我们对每个路径左端点开一个表,储存其右端点
这样我们只需要查询每个路径上点的右端点同时也在路径上的个数
可以用dfs序 + 主席树,每个点u对应的主席树代表着到根节点的右端点的信息。
在更新u时,先继承其父亲版本,然后对于u对应的所有右端点v,在v入度处+1,出序处-1
这样一来对于u和其祖先v,两点之间的有效节点数 = 两点入度之间的值之和
因为假若有一点不在这条路径上,却夹在两点入度之间,那么一定是出入度都在其中,一加一减就没了
如果在这条路径上, 一定只有入度,还没到出度
#include<iostream>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 100005,maxm = 4000005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
int n,m,dfn[maxn],dft[maxn],fa[maxn][18],dep[maxn],cnt,h[maxn],ne = 2;
vector<int> end[maxn];
struct Que{int u,v;}q[maxn];
inline bool operator <(const Que& a,const Que& b){
return a.u == b.u ? a.v < b.v : a.u < b.u;
}
struct EDGE{int to,nxt;}ed[2 * maxn];
void build(int u,int v){
ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
}
int rt[maxn],siz,sum[maxm],ls[maxm],rs[maxm];
int update(int pre,int l,int r,int pos,int v){
int u = ++siz; ls[u] = ls[pre]; rs[u] = rs[pre];
if (l == r) {sum[u] = sum[pre] + v; return u;}
int mid = l + r >> 1;
if (mid >= pos) ls[u] = update(ls[pre],l,mid,pos,v);
else rs[u] = update(rs[pre],mid + 1,r,pos,v);
sum[u] = sum[ls[u]] + sum[rs[u]];
return u;
}
int query(int a,int b,int c,int d,int l,int r,int L,int R){
if (l >= L && r <= R) return sum[a] + sum[b] - sum[c] - sum[d];
int mid = l + r >> 1;
if (mid >= R) return query(ls[a],ls[b],ls[c],ls[d],l,mid,L,R);
else if (mid < L) return query(rs[a],rs[b],rs[c],rs[d],mid + 1,r,L,R);
else return query(ls[a],ls[b],ls[c],ls[d],l,mid,L,R) + query(rs[a],rs[b],rs[c],rs[d],mid + 1,r,L,R);
}
void dfs1(int u){
dfn[u] = ++cnt;
REP(i,17) fa[u][i] = fa[fa[u][i - 1]][i - 1];
Redge(u) if ((to = ed[k].to) != fa[u][0]){
fa[to][0] = u; dep[to] = dep[u] + 1; dfs1(to);
}
dft[u] = ++cnt;
}
void dfs2(int u){
rt[u] = rt[fa[u][0]];
for (unsigned int i = 0; i < end[u].size(); i++){
rt[u] = update(rt[u],1,cnt,dfn[end[u][i]],1);
rt[u] = update(rt[u],1,cnt,dft[end[u][i]],-1);
}
Redge(u) if ((to = ed[k].to) != fa[u][0]) dfs2(to);
}
int Lca(int u,int v){
if (dep[u] < dep[v]) swap(u,v);
for (int i = 0,d = dep[u] - dep[v]; (1 << i) <= d; i++)
if ((1 << i) & d) u = fa[u][i];
if (u == v) return u;
for (int i = 17; i >= 0; i--)
if (fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
return fa[u][0];
}
int solve(int u,int v,int lca){
int o = fa[lca][0],ans = 0;
ans += query(rt[u],rt[v],rt[lca],rt[o],1,cnt,dfn[lca],dfn[u]);
ans += query(rt[u],rt[v],rt[lca],rt[o],1,cnt,dfn[lca],dfn[v]);
ans -= query(rt[u],rt[v],rt[lca],rt[o],1,cnt,dfn[lca],dfn[lca]);
return ans - 1;
}
LL gcd(LL a,LL b){return !b ? a : gcd(b,a % b);}
int main(){
n = read(); m = read();
REP(i,n - 1) build(read(),read());
REP(i,m) q[i].u = read(),q[i].v = read(),end[q[i].u].push_back(q[i].v);
sort(q + 1,q + 1 + m);
dfs1(1); dfs2(1);
LL ans = 0,D = (LL)m * (m - 1) >> 1;
REP(i,m) ans += solve(q[i].u,q[i].v,Lca(q[i].u,q[i].v));
LL d = gcd(ans,D);
printf("%lld/%lld\n",ans / d,D / d);
return 0;
}
BZOJ3772 精神污染 【主席树 + dfs序】的更多相关文章
- BZOJ3772 精神污染 主席树 dfs序
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3772 题意概括 给出一个树,共n个节点. 有m条互不相同的树上路径. 现在让你随机选择2条路径,问 ...
- bzoj 3772 精神污染 主席树+dfs序
精神污染 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 637 Solved: 177[Submit][Status][Discuss] Descri ...
- [BZOJ3772]精神污染 主席树上树+欧拉序
3772: 精神污染 Time Limit: 10 Sec Memory Limit: 64 MB Description 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位 ...
- 51 nod 1681 公共祖先 (主席树+dfs序)
1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...
- 【BZOJ1803】Spoj1487 Query on a tree III 主席树+DFS序
[BZOJ1803]Spoj1487 Query on a tree III Description You are given a node-labeled rooted tree with n n ...
- 【BZOJ 3772】精神污染 主席树+欧拉序
这道题的内存…………………真·精神污染……….. 这道题的思路很明了,我们就是要找每一个路径包含了多少其他路径那么就是找,有多少路径的左右端点都在这条路径上,对于每一条路径,我们随便选定一个端点作为第 ...
- 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)
http://www.spoj.com/problems/COT/ (速度很快,排到了rank6) 这题让我明白了人生T_T 我知道我为什么那么sb了. 调试一早上都在想人生. 唉. 太弱. 太弱. ...
- BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]
传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边 ...
- BZOJ - 2809 dispatching 主席树+dfs序
在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个上级.为保密,同时增强忍者们的 ...
随机推荐
- C# 文件操作概述
微软的.Net框架为我们提供了基于流的I/O操作方式,这样就大大简化了开发者的工作.因为我们可以对一系列的通用对象进行操作,而不必关心该I/O操作是和本机的文件有关还是和网络中的数据有关..Net框架 ...
- JQuery模拟点击页面上的所有a标签,触发onclick事件
注意: 这种方法需要给所有的a标签加上id属性 页面加载完成模拟点击所有的a标签: <script> $(function () { // 模拟点击页面上的所有a标签,触发onclick事 ...
- k8s的service简述
k8s向集群外部暴露端口的3种方式: 1.service->nodePort :仅暴露一个宿主机端口,用于集群外部访问,因为此操作被写入各个节点的iptables或ipvs规则当中,可以用任意一 ...
- 列举Asp.net页面之间传递值的几种方式和优缺点?
一.QueryString变量 优点:使用简单,对于安全性要求不高时传递数字或是文本值非常有效. 缺点:缺乏安全性,由于它的值暴露在浏览器的URL地址中的:不能传递对象. 二. 使用Applicati ...
- 通用后台管理系统源码,响应式布局,Java管理系统源码,零门槛安装部署
本项目是一个通用响应式管理后台,导入开发环境安装就能直接运行,界面也非诚漂亮,在PC端和移动端也是自适应的.非常适合企业或者个人搭建各种商城后台,博客后台,网站管理后台等. 源码启动后的截图 需要这套 ...
- n个人排队都不站在原来的位置
一.题目描述 有n个人首先站成一排,请问,当n个人第二次再重新排列,每个人都不在原来的位置上,问有多少种站法.例如,原来有3个人,ABC,那么第二次每个人都不在原来的位置上有2种站法,BCA和CAB, ...
- (洛谷)P1019 单词接龙
题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙" ...
- mysql--timestamp加减
利用timestamp()对timestamp类型进行秒加减操作: 1.加10秒: 2.减10秒:
- 2940: [Poi2000]条纹(Multi_SG)
2940: [Poi2000]条纹 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 114 Solved: 72[Submit][Status][Dis ...
- NOI p 2017 TG游记
嗨小朋友们大家好 还记得我是谁吗 对了我就是为iot配音的演员 弹鸡鸡 今天呐我特别的要向长沙市的oier们 洛谷的oier们 还有cnblogs的oier们问声好 为什么呢 因为我们在2017年11 ...