【NOIP校内模拟】相遇
【问题描述】
豪哥生活在一个 n 个点的树形城市里面,每一天都要走来走去。虽然走的是比较的 多,但是豪哥在这个城市里面的朋友并不是很多。 当某一天,猴哥给他展现了一下大佬风范之后,豪哥决定要获得一些交往机会来提升交 往能力。豪哥现在已经物色上了一条友,打算和它(豪哥并不让吃瓜群众知道性别)交 往。豪哥现在 spy 了一下这个人的所有行程起点和终点,豪哥打算从终点开始走到起点与 其相遇。但是豪哥是想找话题的,他想知道以前有多少次行程和此次行程是有交集的,这 样豪哥就可以搭上话了。这个路径与之前路径的有交集数量作为豪哥此次的交往机会。 但是豪哥急着要做交往准备,所以算什么交往机会的小事情就交给你了。
【输入】 第一行一个正整数 n 表示节点个数。接下来 n-1 行,每行两个正整数分别是 u, v 表示节点 u 和 v之间有连边。接下来一行一个 正整数 m表示路径个数。然后有 m行,每行两个正整 数分别是 u, v分别表示 u到 v之间有一条路径。
【输出】 输出共 m行,每行一个整数,第 i行表示豪哥在这条路径上获得的交往机会。
【输入样例】 5 1 2 1 3 3 4 3 5 4 4 5 4 2 1 3 1 2
【输出样例】 0 1 2 2
【数据范围与约定】 对于 20%的数据 n, m≤2000 对于另外 20%的数据 n, m≤50000 对于另外 10%的数据 n, m≤200000 保证树形结构是一条链 对于另外 50%的数据 n, m≤200000
拿到题目的一瞬间 我就想起了之前做的一道树上差分lca来统计每个点被经过的次数(好像叫松鼠的新家来着
然而这道题好像又不一样,不能最后dfs扫一遍统计前缀和
我就YY是不是要树链剖分维护 然后怒码200行lca+树剖
成功的WA掉样例 然后就弃疗了 。。
其实正解是差不多的 发现我是少讨论了一种情况
如果两段路径有交,则其中一段路径的LCA在另外一段路径上。
然后分两种情况讨论
1)当前路径有之前的LCA
2)当前LCA在之前的路径上
对一条路径x,y,设lca=z
对于情况1
查询到x,y到根节点的lca的个数,相加起来,再减去2*z到根节点的lca的个数
修改需要给x~y区间(dfs序下)到根节点的lca的个数+1 其实就是一个单点查询+区间修改,考虑树状数组完成
对于情况2 求出z的子树前缀和
修改就在x,y上面打一个+1的标记,在z上面打一个-2的标记,这样就将整条链都+1了。
其实就是一个单点修改+区间查询,也是树状数组
草真是绕的一批
#include<bits/stdc++.h> #define lowbit(x) x&(-x) #define N 200005 #define M 200005 using namespace std; struct node { int to,next; }edge[2*M]; int n,tot,first[N],m; inline void addedge(int x,int y) { tot++; edge[tot].to=y; edge[tot].next=first[x]; first[x]=tot; } int up[N][22],depth[N]; int st[N],ed[N],dfn,val[N]; void dfs(int now,int fa) { st[now]=++dfn; up[now][0]=fa; depth[now]=depth[fa]+1; for(int i=1;i<=20;i++) up[now][i]=up[up[now][i-1]][i-1]; for(int u=first[now];u;u=edge[u].next) { int vis=edge[u].to; if(vis==fa) continue; dfs(vis,now); } ed[now]=dfn; } int lca(int x,int y) { if(depth[x]<depth[y]) swap(x,y); //x比y深 for(int i=20;i>=0;i--) { if(depth[up[x][i]]>=depth[y]) x=up[x][i]; } if(x==y) return x; for(int i=20;i>=0;i--) { if(up[x][i]!=up[y][i]) { x=up[x][i]; y=up[y][i]; } } return up[x][0]; } struct BIT { int T[N]; inline void add(int x,int delta) { for(int i=x;i<=n;i+=lowbit(i)) T[i]+=delta; } inline int query(int x) { int ans=0; for(int i=x;i>0;i-=lowbit(i)) ans+=T[i]; return ans; } }A,B; inline int getans(int x,int y,int z) { return A.query(st[x])+A.query(st[y])-2*A.query(st[z])+B.query(ed[z])-B.query(st[z]-1)+val[z]; } int main() { ios::sync_with_stdio(false); cin.tie(NULL),cout.tie(NULL); cin>>n; for(int i=1;i<=n-1;i++) { int x,y; cin>>x>>y; addedge(x,y); addedge(y,x); } dfs(1,0); cin>>m; for(int i=1;i<=m;i++) { int x,y,z; cin>>x>>y; z=lca(x,y); cout<<getans(x,y,z)<<'\n'; val[z]++; A.add(st[z],1); A.add(ed[z]+1,-1); B.add(st[x],1); B.add(st[y],1); B.add(st[z],-2); } return 0; }