BZOJ 3772 精神污染 主席树+欧拉序
Description
Input
Output
Sample Input
1 2
2 3
3 4
2 5
3 5
2 5
1 4
Sample Output
样例解释
可以选择的路径对有(1,2),(1,3),(2,3),只有路径1完全覆盖路径2。
附:这道题真的是精神污染
机房的人RE和MLE记录:
我们可以通过两种方式计算答案:
1.算出每条路径覆盖几条路径
2.计算每条路径被几条路径覆盖
那么这道题是从第一个角度考虑,对于一条路径(u,v)任意选取一个端点,假设把u作为端点,把v塞入u的动态数组中,然后对整颗树进行dfs,求出欧拉序,再对整棵树进行第二遍dfs,把动态数组中对应的节点在L处加1,R处减1,那么在统计答案的时候对选定端点的限制体现在主席树选用的根为root[u],root[v],root[lca(u,v)],root[f[lca(u,v)][0]],限制了选定端点,然后进行区间查询,查询[L[lca],L[u]]和[L[lca],L[v]],因为L[lca]被算了两遍,所以要再次减去L[lca]的贡献,而且不能算上自己在L[u]或L[v]的贡献,然后Ans需要减1,然后就得到答案了。炸int注意。。。
code:
#include <stdio.h>
#include <cstring>
#include <vector>
const int MAXN = 100005;
typedef long long ll;
int first[MAXN],e=1,deep[MAXN],f[MAXN][20],size,cnt,root[MAXN],L[MAXN],R[MAXN],n,m;
std :: vector<int>G[MAXN];template<typename _t>
inline _t read(){_t x=0,f=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48);return x*f;
}
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}struct node{int l,r,sum;
}tree[MAXN*39];void insert(int &o,int old,int l,int r,int pos,int val){o=++cnt;tree[o]=tree[old];tree[o].sum+=val;if(l==r)return;int m=l+r>>1;if(pos<=m)insert(tree[o].l,tree[old].l,l,m,pos,val);else insert(tree[o].r,tree[old].r,m+1,r,pos,val);
}#define l(x) tree[x].l
#define r(x) tree[x].r
#define s(x) tree[x].suminline ll Query(int t1,int t2,int t3,int t4,int x,int y,int l,int r){if(x<=l&&r<=y)return s(t1)+s(t2)-s(t3)-s(t4);ll Ans = 0;int m=l+r>>1; if(x<=m)Ans+=Query(l(t1),l(t2),l(t3),l(t4),x,y,l,m);if(m<y)Ans+=Query(r(t1),r(t2),r(t3),r(t4),x,y,m+1,r);return Ans;
}struct edge{int v,next;
}a[MAXN<<1];struct Query{int x,y;
}q[MAXN];inline void push(int u,int v){a[e].v=v;a[e].next=first[u];first[u]=e++;
}void dfs(int u,int fa){L[u]=++size;f[u][0]=fa;deep[u]=deep[fa]+1;for(int i=1;i<=17;i++)f[u][i]=f[f[u][i-1]][i-1];for(int i=first[u];i;i=a[i].next)if(a[i].v!=fa)dfs(a[i].v,u);R[u]=++size;return;
}void __dfs(int u){root[u]=root[f[u][0]];for(int i=0;i<G[u].size();i++)insert(root[u],root[u],1,size,L[G[u][i]],1),insert(root[u],root[u],1,size,R[G[u][i]],-1);for(int i=first[u];i;i=a[i].next)if(a[i].v!=f[u][0])__dfs(a[i].v);
}inline int lca(int u,int v){if(deep[u]<deep[v]){u^=v;v^=u;u^=v;}int t=deep[u]-deep[v];for(int i=0;i<=17;i++)if(t&(1<<i))u=f[u][i];if(u==v)return u;for(int i=17;i>=0;i--)if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];return f[u][0];
}int main(){ n=read<int>();m=read<int>();for(int i=1;i<n;i++){int u=read<int>(),v=read<int>();push(u,v);push(v,u);}dfs(1,0);for(int i=1;i<=m;i++)q[i].x=read<int>(),q[i].y=read<int>(),G[q[i].x].push_back(q[i].y);__dfs(1);ll Ans = 0;for(int i=1;i<=m;i++){int Lca=lca(q[i].x,q[i].y);int t1=root[q[i].x],t2=root[q[i].y],t3=root[Lca],t4=root[f[Lca][0]];Ans+=Query(t1,t2,t3,t4,L[Lca],L[q[i].x],1,size);Ans+=Query(t1,t2,t3,t4,L[Lca],L[q[i].y],1,size);Ans-=Query(t1,t2,t3,t4,L[Lca],L[Lca],1,size);Ans--;}if(Ans==0){printf("0/1\n");return 0;}ll tmp = gcd(Ans,(ll)m*(m-1)/2);printf("%lld/%lld\n",Ans/tmp,(ll)m*(m-1)/2/tmp);
}
BZOJ 3772 精神污染 主席树+欧拉序相关推荐
- 树的遍历顺序 - dfs序|欧拉序|dfn序(备忘)
(仅作备忘) dfs序是dfs过程中对于某节点进入这个节点的子树和离开子树的顺序 满足每个节点都会在dfs序上出现恰好两次 任意子树的dfs序都是连续的 欧拉序是dfs过程中经过节点的顺序 每个节点至 ...
- 【香蕉oi】Tree(欧拉序、线段树)
文章目录 题意 思路 1 2 注意 代码 题意 一棵以1为根的有根树,每条边有边权. 有3种操作: 修改一条边xxx的权值为yyy. 询问以xxx为根的子树中的一点uuu和以yyy为根的子树中一点vv ...
- 图论——Tarjan 初步 DFS序+时间戳+欧拉序
一.什么是DFS序: DFS序是按照先序遍历,先遍历根节点然后依次遍历左子树,右子树的过程,每次遇到新的节点就把新访问节点加到序列中,代码如下: int DFSrk[100000]; int cnt= ...
- jzoj3794,P1383-高级打字机【欧拉序,离线O(n)】
正题 题目链接:https://www.luogu.org/problemnew/show/P1383 大意 三个操作 T c:加入一个字符c U x:撤销前x次操作(只包括T和U) Q x:询问当前 ...
- 跑步爱天天(欧拉序入门)
考试的时候已经处理出了欧拉序,但并没有关注到它的种种性质 这里给出欧拉序的定义与运用 树的欧拉序是对树进行DFS的一种序列. 有两种形式: 1.在每个结点进和出都加进序列. 2.只要到达每一个结点就把 ...
- [BZOJ 4034][HAOI2015]树上操作(欧拉序列+线段树)
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...
- bzoj 1409 Password 矩阵快速幂+欧拉函数
可以发现,该数组的mi就是斐波那契数列 所以要矩阵快速幂搞出第n位 但是斐波那契数列上涨的很快,这就需要欧拉定理了 p^phi(q)%q=1(gcd(p,q)==1) p是素数,所以可以用 然后需要5 ...
- bzoj 4012: [HNOI2015]开店 主席树
Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...
- Codeforces Round #538 (Div. 2) F. Please, another Queries on Array? 线段树 + 欧拉函数
传送门 文章目录 题意: 思路: 题意: 给你一个序列aaa,你需要实现两种操作: (1)(1)(1) 将[l,r][l,r][l,r]的aia_iai都乘rrr. (2)(2)(2) 求ϕ(∏i= ...
- BZOJ.3524.[POI2014]Couriers(主席树)
题目链接 //119964kb 5780ms //主席树裸题啊.. #include <cstdio> #include <cctype> #define gc() getch ...
最新文章
- 特性(C# 和 Visual Basic)
- stl-vector详解
- Python Django后台管理模板美化:使用django-simpleui模块
- 深入浅出剖析 OpenCV 视觉处理
- 初学者选黑卡还是微单_零基础,一篇读懂单反和微单
- 安装Bootstrap3源码版本
- 担心再次被起诉?马斯克已删除特斯拉可能几个月内成为最大公司推文
- 华北电力大学依托大数据实施精准资助
- UG NX 12 取消选择对象
- ESP32直接烧写bin文件
- 因机构系统维护服务暂不可用_因合作方系统维护,暂时无法使用是什么意思?...
- linux 安装minio并设置开机自启动
- [译]尤雨溪: Ref语法糖提案
- UDS的19 04读取快照信息解析
- 利用Javascript生成txt文本文件
- 【转】【Grub2】UEFI添加grub2引导
- 推荐一个基于 Spring Boot+MyBatis Plus+JWT 的问卷系统!
- 数组中的最大值/最小值
- 单片机VIN VOUT VCC GND是什么
- python语句中print(0xa+0xb)的输出结果是_【单选题】Python语句print(0xA+0xB)的输出结果是( )...