题意

给定一棵树和若干条路线,每条路线相当于树上 x,y 之间的路径,途径路径上的每个点
给出若干个询问,每次询问从 u 到 v 至少需要利用几条路线
N,M,Q≤200000

题解

构建倍增数组g[i][j]表示从i点向上经过j条线路能到达的深度最小的点。
所以对于每一对询问的x,y,我们贪心地把它们提到深度大于等于lca地最大的点。记为x‘,y'然后判断是否有路径经过x’和y‘
然后各种情况特判(无解,x‘,y’为lca,有无路径经过x‘,y’)
然后对于判断是否路径经过x‘,y’。
可以用树状数组维护 DFS 序
DFS 遍历整棵树,递归进入 x 时,扫描路线 (x,y),把 y 在 DFS 序上对应位置 +1,
x,y 可直达,当且仅当 x 子树中的节点使 DFS 序上 y 对应区间的和发生了变化
(调了半天代码最后没调出来,最后屈辱地看了题解)
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const int N=;
const int D=;
struct node{
int a,b;
};
vector<int> road[N],h[N];
vector<node> q[N];
int n,m,t,fa[N][D+],w[N][D+],head[N],sum[N],ans[N],g[N];
int cnt,tot,dep[N],id[N],size[N],c[N];
int lowbit(int x){
return x&-x;
}
void update(int x){
for(int i=x;i<=n;i+=lowbit(i)){
c[i]+=;
}
}
int check(int x){
int tmp=;
for(int i=x;i>=;i-=lowbit(i)){
tmp+=c[i];
}
return tmp;
}
struct edge{
int to,nxt;
}e[N*];
void add(int u,int v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs1(int u,int deep){
dep[u]=deep;
id[u]=++tot;
size[u]=;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[u][])continue;
dfs1(v,deep+);
size[u]+=size[v];
}
}
void dfs2(int u){
g[u]=u;
// cout<<u<<"ksdjfksdf"<<endl;
for(int i=;i<h[u].size();i++){
// cout<<h[u][i]<<endl;
if(dep[h[u][i]]<dep[g[u]])g[u]=h[u][i];
}
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
// cout<<v<<" "<<fa[u][0]<<endl;
if(v==fa[u][])continue;
dfs2(v);
if(dep[g[v]]<dep[g[u]])g[u]=g[v];
}
w[u][]=g[u];
}
int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=D;i>=;i--){
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
}
if(x==y)return x;
for(int i=D;i>=;i--){
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
}
return fa[x][];
}
node work(int x,int LCA){
if(x==LCA)return (node){x,};
int tmp=;
for(int i=D;i>=;i--)
if(dep[w[x][i]]>dep[LCA])x=w[x][i],tmp+=(<<i);
if(w[x][]==x)return (node){x,-};
return (node){x,tmp};
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&fa[i][]);
add(fa[i][],i);
add(i,fa[i][]);
}
dfs1(,);
for(int i=;i<=D;i++)
for(int j=;j<=n;j++){
fa[j][i]=fa[fa[j][i-]][i-];
}
scanf("%d",&m);
for(int i=;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
int c=lca(x,y);
// cout<<c<<endl;
if(id[x]>id[y])swap(x,y);
road[id[x]].push_back(id[y]);
if(dep[c]<dep[x])h[x].push_back(c);
if(dep[c]<dep[y])h[y].push_back(c);
}
dfs2();
for(int i=;i<=n;i++){
// cout<<g[i]<<endl;
}
for(int i=;i<=D;i++)
for(int j=;j<=n;j++){
w[j][i]=w[w[j][i-]][i-];
// cout<<w[j][i]<<endl;
}
scanf("%d",&t);
for(int i=;i<=t;i++){
int x,y;
scanf("%d%d",&x,&y);
int c=lca(x,y);
node A=work(x,c);
node B=work(y,c);
if(A.b==-||B.b==-){
ans[i]=-;
continue;
}
if(x==c||y==c){
ans[i]=A.b+B.b+;
continue;
}
ans[i]=A.b+B.b+;
x=A.a;
y=B.a;
if(id[x]>id[y])swap(x,y);
q[id[x]-].push_back((node){y,-i});
q[id[x]+size[x]-].push_back((node){y,i});
}
for(int i=;i<=n;i++){
for(int j=;j<road[i].size();j++)update(road[i][j]);
for(int j=;j<q[i].size();j++){
int num=(q[i][j].b>?:-);
int x=q[i][j].a;int y=q[i][j].b*num;
sum[y]+=num*(check(id[x]+size[x]-)-check(id[x]-));
}
}
for(int i=;i<=t;i++){
printf("%d\n",ans[i]-(sum[i]>));
}
return ;
}

CF983E NN country(倍增,差分)的更多相关文章

  1. cf983E NN Country (倍增+dfs序+树状数组)

    首先可以求出从某点做$2^k$次车能到的最浅的点,这个只要dfs一下,把它的孩子能到的最浅的点更新过来就可以 然后倍增地往上跳,不能跳到lca的上面,记录坐车的次数ans 此时有三种情况(设最远能跳到 ...

  2. [CF983E]NN country

    题意:给一棵树,有许多条巴士线路$(a_i,b_i)$(巴士在路径上每个点都会停车),多次询问从一点到另一点最少要坐多少次巴士 首先dfs一遍预处理出一个点向上坐$2^k$次巴士能到的最浅点,于是我们 ...

  3. 【CodeForces】983 E. NN country 树上倍增+二维数点

    [题目]E. NN country [题意]给定n个点的树和m条链,q次询问一条链(a,b)最少被多少条给定的链覆盖.\(n,m,q \leq 2*10^5\). [算法]树上倍增+二维数点(树状数组 ...

  4. 【codeforces 983E】NN country

    Description In the NN country, there are n cities, numbered from 1 to n, and n−1 roads, connecting t ...

  5. Codeforces 983E - NN country(贪心+倍增优化)

    Codeforces 题面传送门 & 洛谷题面传送门 一道(绝对)偏简单的 D1E,但是我怕自己过若干年(大雾)忘了自己的解法了,所以过来水篇题解( 首先考虑怎么暴力地解决这个问题,不难发现我 ...

  6. NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分

    原文链接https://www.cnblogs.com/zhouzhendong/p/9275606.html 题目传送门 - 洛谷P1600 题目传送门 - LOJ#2359 题目传送门 - Vij ...

  7. NOIP2015 运输计划 - 二分 + 树链剖分 / (倍增 + 差分)

    BZOJ CodeVS Uoj 题目大意: 给一个n个点的边带权树,给定m条链,你可以选择树中的任意一条边,将它置为0,使得最长的链长最短. 题目分析: 最小化最大值,二分. 二分最短长度mid,将图 ...

  8. Codeforces983E. NN country

    新鲜出炉! $n \leq 200000$的树,给$m \leq 200000$条链,$q \leq 200000$个询问,每次问一条询问链最少用m条中的几条给定链覆盖其所有边,可能无解. 首先确定一 ...

  9. 多校联训 DS 专题

    CF1039D You Are Given a Tree 容易发现,当 \(k\) 不断增大时,答案不断减小,且 \(k\) 的答案不超过 \(\lfloor\frac {n}{k}\rfloor\) ...

随机推荐

  1. webpack的像素转vw loader插件

    这是一款针对webpack的像素转vw单位的loader插件. 笔者公司中,h5 rem的开发方案目前已经渐渐开始转向vw方案,因此本工具应运而生. 目前所制作的h5,大部分设计稿分辨率都是750的宽 ...

  2. vs2015汉化

    VS2015汉化 VS2015安装打开后默认是英文的,将它改成中文的VS 1.安装下载好的语言包进行安装 2.正在安装 3.安装完成后关闭 4.打开VS2015默认不是中文的,点击Tools--> ...

  3. Android ViewPager 动画效果

    找到个不错的开源项目:https://github.com/jfeinstein10/JazzyViewPager Android ViewPager 动画效果   

  4. double int 类型的区别

    内部组织格式不同: po [NSString stringWithFormat:@"%d", f] 107886912 (lldb) po [NSString stringWith ...

  5. 使用了未经检查或不安全的操作。有关详细信息, 请使用 -Xlint:unchecked 重新编译。

    警告信息如下:

  6. span文本自动换行

    .span{ word-wrap: break-word; word-break: break-all; overflow: hidden; }

  7. 【BZOJ4940】【YNOI2016】这是我自己的发明

    阅读此篇文章前请先跟我大喊三声:dllxl!dllxl!dllxl! 咳咳. 题意: Description 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1. 将树根换为 x. ...

  8. BZOJ2870 最长道路tree(并查集+LCA)

    题意 (n<=50000) 题解 #include<iostream> #include<cstring> #include<cstdio> #include ...

  9. windows下matlab代码到ubuntu下中文注释出现乱码

    转自:https://blog.csdn.net/kouyi5627/article/details/81513329 环境:Ubuntu18.04,Matlab R2017b. 把matlab文件从 ...

  10. 【转载】02-PowerDesigner的下载及安装

    原创路径:https://blog.csdn.net/ruyu00/article/details/79842807 一.下载 下载路径:https://pan.baidu.com/s/1WD7QHT ...