首先,我们从 u -> v 有一个明显的贪心,即能向上跳的时候尽量向深度最浅的节点跳。这个我们可以用树上倍增来维护。我们可以认为 u 贪心向上跳后不超过 lca 能跳到 u' 的位置, v 跳到 v' 的位置,这时只需要查询一下是否有 u' -> v' 的直达公交线路就可以确定出答案了。

  如果 u 和 v 在一条链上,我们可以直接倍增获得答案,所以以下讨论均为 u != lca && v != lca 的情况。 若在节点 u 和 v 之间存在一条直达线路,说明有一条线路的起点在以 u 为根的子树内,重点在以 v 为根的子树内。即起点的dfs序 >= dfn[u] && <= dfn[u] + size[u] - 1, 终点的 dfs序 >= dfn[v] && <= dfn[v] + size[v] -1;这是一个二维限制的问题,暴力主席树就可以搞定……

  之后看题解发现其实有一种妙妙的做法并不需要主席树。我们可以离线处理。要查询是否有起点在 u 的子树内且终点在 v 的子树内的路线,就是dfs在进入 u 的子树内之前记录下 v 的子树内此时记录的路径数,然后进入子树,遇到路线则标记终点所在的位置。返回之后两相对比,如果此时 v 的子树内记录的路径数有增长的话说明这样的路线是存在的。

#include <bits/stdc++.h>
using namespace std;
#define maxn 450000
#define INF 99999999
#define CNST 20
int n, m, q, Mul[maxn][CNST], gra[maxn][CNST];
int dfn[maxn], dep[maxn], bits[];
int tot, timer, root[maxn], fa[maxn], size[maxn]; int read()
{
int x = , k = ;
char c; c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} struct edge
{
int cnp, to[maxn], last[maxn], head[maxn];
edge() { cnp = ; }
void add(int u, int v)
{ to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++; }
}E1, G; struct edge1
{
int u, v;
edge1(int _u = , int _v = ) { u = _u, v = _v; }
friend bool operator <(const edge1& a, const edge1& b)
{ return (dfn[a.u] != dfn[b.u]) ? dfn[a.u] < dfn[b.u] : dfn[a.v] < dfn[b.v]; }
}e[maxn]; struct node
{
int u, num;
node(int _u = , int _num = )
{ u = _u, num = _num; }
}; struct node1
{
int sum, ls, rs;
}T[maxn * ]; void dfs(int u)
{
gra[u][] = fa[u], dfn[u] = ++ timer; size[u] = ;
for(int i = ; i < CNST; i ++) gra[u][i] = gra[gra[u][i - ]][i - ];
for(int i = E1.head[u]; i; i = E1.last[i])
{
int v = E1.to[i];
dep[v] = dep[u] + ; dfs(v);
size[u] += size[v];
}
} int dfs2(int u)
{
int lim = ;
for(int i = G.head[u]; i; i = G.last[i])
{
if(u != G.to[i]) lim = (dep[lim] < dep[G.to[i]]) ? lim : G.to[i];
if(!lim && u != G.to[i]) lim = G.to[i];
}
for(int i = E1.head[u]; i; i = E1.last[i])
{
int v = E1.to[i];
int t = dfs2(v);
if(u != t && t) lim = (dep[lim] < dep[t]) ? lim : t;
if(!lim && u != t) lim = t;
}
Mul[u][] = lim;
return lim;
} void dfs3(int u)
{
for(int i = ; i < CNST; i ++)
Mul[u][i] = Mul[Mul[u][i - ]][i - ];
for(int i = E1.head[u]; i; i = E1.last[i])
dfs3(E1.to[i]);
} int LCA(int u, int v)
{
if(dep[u] < dep[v]) swap(u, v);
for(int i = CNST - ; ~i; i --)
if(dep[gra[u][i]] >= dep[v]) u = gra[u][i];
for(int i = CNST - ; ~i; i --)
if(gra[u][i] != gra[v][i]) u = gra[u][i], v = gra[v][i];
return (u == v) ? u : gra[u][];
} node Jump(int u, int fu)
{
bool flag = ; int cnt = ;
if(dep[u] == dep[fu]) flag = ;
for(int i = CNST - ; ~i; i --)
{
if(!Mul[u][i]) continue;
if(dep[Mul[u][i]] <= dep[fu]) flag = ;
if(dep[Mul[u][i]] > dep[fu]) u = Mul[u][i], cnt += bits[i];
}
if(!flag) return node(-, );
else return node(u, cnt);
} void Ins(int &now, int pre, int l, int r, int x)
{
now = ++ tot; T[now] = T[pre]; T[now].sum ++;
if(l == r) return;
int mid = (l + r) >> ;
if(x <= mid) Ins(T[now].ls, T[pre].ls, l, mid, x);
else Ins(T[now].rs, T[pre].rs, mid + , r, x);
} bool Query(int now, int pre, int l, int r, int L, int R)
{
if(!now) return ;
if(L == l && R == r) return (T[now].sum - T[pre].sum);
if(L > r || R < l) return ;
int mid = (l + r) >> ;
if(R <= mid) return Query(T[now].ls, T[pre].ls, l, mid, L, R);
else if(L > mid) return Query(T[now].rs, T[pre].rs, mid + , r, L, R);
else
{
if(Query(T[now].ls, T[pre].ls, l, mid, L, mid)) return ;
else return Query(T[now].rs, T[pre].rs, mid + , r, mid + , R);
}
} int main()
{
n = read();
bits[] = ; for(int i = ; i < CNST; i ++) bits[i] = bits[i - ] << ;
for(int i = ; i <= n; i ++)
{
fa[i] = read();
E1.add(fa[i], i);
}
dep[] = ; dfs();
m = read();
for(int i = ; i <= m; i ++)
{
int u = read(), v = read(), lca = LCA(u, v);
G.add(u, lca); G.add(v, lca);
e[i] = edge1(u, v);
}
dfs2(); dfs3();
sort(e + , e + + m); int last = ; root[] = tot = ;
for(int i = ; i <= m; i ++)
{
while(last < dfn[e[i].u] - ) T[root[last + ] = ++ tot] = T[root[last]], last ++;
Ins(root[dfn[e[i].u]], root[last], , n, dfn[e[i].v]);
if(last != dfn[e[i].u]) last ++;
}
while(last + <= n) T[root[last + ] = ++ tot] = T[root[last]], last ++;
q = read();
for(int i = ; i <= q; i ++)
{
int u = read(), v = read(), lca = LCA(u, v);
node a = Jump(u, lca), b = Jump(v, lca);
int fu = a.u, fv = b.u;
if(fu == - || fv == -) { printf("-1\n"); continue; }
if(u == lca || v == lca) { printf("%d\n", a.num + b.num + ); continue; }
int l1 = dfn[fu], r1 = dfn[fu] + size[fu] - ;
int l2 = dfn[fv], r2 = dfn[fv] + size[fv] - ;
int x = Query(root[r1], root[l1 - ], , n, l2, r2);
int y = Query(root[r2], root[l2 - ], , n, l1, r1); printf("%d\n", a.num + b.num + + !(x || y));
}
return ;
}

【题解】CF#983 E-NN country的更多相关文章

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

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

  2. 【codeforces 983E】NN country

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

  3. 竞赛题解 - CF Round #524 Div.2

    CF Round #524 Div.2 - 竞赛题解 不容易CF有一场下午的比赛,开心的和一个神犇一起报了名 被虐爆--前两题水过去,第三题卡了好久,第四题毫无头绪QwQ Codeforces 传送门 ...

  4. 题解——CF Manthan, Codefest 18 (rated, Div. 1 + Div. 2) T5(思维)

    还是dfs? 好像自己写的有锅 过不去 看了题解修改了才过qwq #include <cstdio> #include <algorithm> #include <cst ...

  5. 竞赛题解 - [CF 1080D]Olya and magical square

    Olya and magical square - 竞赛题解 借鉴了一下神犇tly的博客QwQ(还是打一下广告) 终于弄懂了 Codeforces 传送门 『题目』(直接上翻译了) 给一个边长为 \( ...

  6. Codeforces983E. NN country

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

  7. CF983E NN country(倍增,差分)

    题意 给定一棵树和若干条路线,每条路线相当于树上 x,y 之间的路径,途径路径上的每个点 给出若干个询问,每次询问从 u 到 v 至少需要利用几条路线 N,M,Q≤200000 题解 构建倍增数组g[ ...

  8. [题解] [CF 1250J] The Parade

    题面 题目大意: 给定一个 \(n\) , 所有军人的数量均在 \([1, n]\) 给定 \(a_i\) 代表高度为 \(i\) 的军人的个数 你要将这些军人分成 \(k\) 行, 满足下面两个条件 ...

  9. 题解 CF 1372 B

    题目 传送门 题意 给出 \(n\),输出 \(a\) ,\(b\) (\(0 < a \leq b < n\)),使\(a+b=n\)且 \(\operatorname{lcm}(a,b ...

随机推荐

  1. 【POJ2182】Lost Cows

    [POJ2182]Lost Cows 题面 vjudge 题解 从后往前做 每扫到一个点\(i\)以及比前面小的有\(a[i]\)个数 就是查询当前的第\(a[i]+1\)小 然后查询完将这个数删掉 ...

  2. sublime安装php_beautifier来格式化PHP代码

    注:如果你使用sublime3,php版本是5.6以上,推荐使用这个插件phpfmt 环境 操作系统:windows7 sublime版本:2.0.2 PHP安装路径: D:\wamp\bin\php ...

  3. What is the "internal" interface and port for on Openvswitch?

    转:https://ask.openstack.org/en/question/4276/what-is-the-internal-interface-and-port-for-on-openvswi ...

  4. 引领技术变革,腾讯云、腾讯WeTest和英特尔,合作布局云游戏

    WeTest 导读 ChinaJoy作为中国泛娱乐产业年度风向标,受到全球业界的高度关注.在本届ChinaJoy上,腾讯云.腾讯WeTest和英特尔,合作为游戏玩家.游戏开发者等业界人士联合展出了云游 ...

  5. 如何编写 Python 程序

    如何编写 Python 程序 从今以后,保存和运行 Python 程序的标准步骤如下: 对于 PyCharm 用户 打开 PyCharm. 以给定的文件名创建新文件. 输入案例中给出的代码. 右键并运 ...

  6. 使用maven构建web项目(简易版)

    在eclipse中使用maven开发一个web项目 第一步:安装maven:在Windows上安装Maven 中间省略很多步骤....(包括关于eclipse中配置maven) 第二步:不用懂任何ma ...

  7. CSP201709-1:打酱油

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  8. 【MFC】学习与问题整合

    需要源码联系邮件:kangxlchn@163.com 1.新建一个MFC工程(基于对话框) 环境:vs2017 统统NEXT 新建完成后打开MFCPrj.cpp文件 打开类试图 每创建一个MFC项目, ...

  9. 【Paper】Deep & Cross Network for Ad Click Predictions

    目录 背景 相关工作 主要贡献 核心思想 Embedding和Stacking层 交叉网络(Cross Network) 深度网络(Deep Network) 组合层(Combination Laye ...

  10. iOS开发Interface Builder技巧

    1.使view的Size与view中的Content相适应:选中任意的一个view,然后Editor->Size to Fit Content,或者简单的按 ⌘=接着就会按照下面的规则对选中vi ...