题解 [CF983E] NN country

传送门

为啥题解的思路引入都是从两边向中间贪心啊
为啥只有我想的是从左往右贪心啊

好的首先如果只有一次询问的话那么可以贪心走连续段
然后想要优化每次走连续段的过程
那么我们肯定是要对着一些固定的且可拼合的路径预处理跳连续段的结果
考虑对每个点倍增预处理向上跳 \(2^k\) 个连续段最高能到达的节点,然后在 lca 处合并
发现合并的时候需要能够判断路径 \((u, v)\) 是否能被给定的一些路径 \((a, b)\) 中的某条完全覆盖
利用预处理的倍增数组处理掉 \(u, v\) 有祖先关系的
剩下的相当于要 \(a, b\) 分别在 \(u, v\) 子树中,可以放到 dfs 序上二维数点
复杂度 \(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, q;
bool vis[N];
struct qes{int l, r, id;};
vector<qes> add[N], del[N];
vector<int> road[N], ers[N];
vector<pair<int, int>> que[N];
int head[N], dep[N], lg[N], fa[21][N], top[21][N], ans[N], bit[N], id[N], siz[N], rec[N], rk[N], cover[N], ecnt, tot;
struct cmp{inline bool operator () (int a, int b) const {return dep[a]<dep[b];}};
multiset<int, cmp> s[N];
struct edge{int to, next;}e[N<<1];
inline void link(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}
inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) bit[i]+=dat;}
inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
inline int query(int l, int r) {
	int ans=0; --l;
	while (r>l) ans+=bit[r], r-=r&-r;
	while (l>r) ans-=bit[l], l-=l&-l;
	return ans;
}

void dfs1(int u) {
	siz[u]=1; rk[id[u]=++tot]=u;
	for (int i=1; i<21; ++i)
		if (dep[u]>=1<<i) fa[i][u]=fa[i-1][fa[i-1][u]];
		else break;
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		dep[v]=dep[u]+1;
		fa[0][v]=u;
		dfs1(v);
		siz[u]+=siz[v];
	}
}

int lca(int a, int b) {
	if (dep[a]<dep[b]) swap(a, b);
	while (dep[a]>dep[b]) a=fa[lg[dep[a]-dep[b]]-1][a];
	if (a==b) return a;
	for (int i=lg[dep[a]]-1; ~i; --i)
		if (fa[i][a]!=fa[i][b])
			a=fa[i][a], b=fa[i][b];
	return fa[0][a];
}

void dfs2(int u) {
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		dfs2(v);
		if (s[u].size()<s[v].size()) swap(s[u], s[v]);
		for (auto it:s[v]) s[u].insert(it);
	}	
	for (auto v:road[u]) {
		int t=lca(u, v);
		if (u!=t) s[u].insert(t), ers[t].pb(t);
	}
	for (auto it:ers[u]) s[u].erase(it);
	if (s[u].size()) top[0][u]=*s[u].begin();
}

void dfs3(int u) {
	for (int i=1; i<21; ++i) top[i][u]=top[i-1][top[i-1][u]];
	for (int i=head[u],v; ~i; i=e[i].next) dfs3(e[i].to);
}

signed main()
{
	n=read();
	memset(head, -1, sizeof(head));
	for (int i=2; i<=n; ++i) link(read(), i);
	for (int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	m=read();
	for (int i=1,a,b; i<=m; ++i) {
		a=read(); b=read();
		road[a].pb(b); road[b].pb(a);
	}
	dep[1]=1; dfs1(1); dfs2(1); dfs3(1);
	q=read();
	for (int i=1; i<=n; ++i) add[i].clear(), del[i].clear();
	for (int i=1,u,v; i<=q; ++i) {
		// cout<<"i: "<<i<<endl;
		u=read(); v=read();
		int t=lca(u, v);
		// cout<<"t: "<<t<<endl;
		for (int j=20; ~j; --j) if (dep[top[j][u]]>dep[t]) u=top[j][u], ans[i]+=1<<j;
		for (int j=20; ~j; --j) if (dep[top[j][v]]>dep[t]) v=top[j][v], ans[i]+=1<<j;
		// cout<<"uv: "<<u<<' '<<v<<' '<<ans[i]<<endl;
		if (dep[u]>dep[v]) swap(u, v);
		if (u==t&&top[0][v]) ++ans[i];
		else if (!top[0][u]||!top[0][v]) ans[i]=-1;
		else {
			vis[i]=1; ans[i]+=2;
			del[id[u]-1].pb({id[v], id[v]+siz[v]-1, i});
			add[id[u]+siz[u]-1].pb({id[v], id[v]+siz[v]-1, i});
		}
	}
	for (int i=1; i<=n; ++i) {
		for (auto it:road[rk[i]]) upd(id[it], 1);
		for (auto it:add[i]) cover[it.id]+=query(it.l, it.r);
		for (auto it:del[i]) cover[it.id]-=query(it.l, it.r);
	}
	for (int i=1; i<=q; ++i) if (vis[i]) ans[i]-=bool(cover[i]);
	for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);

	return 0;
}
posted @ 2022-05-13 21:14  Administrator-09  阅读(1)  评论(0编辑  收藏  举报