题意:给一棵树,有许多条巴士线路$(a_i,b_i)$(巴士在路径上每个点都会停车),多次询问从一点到另一点最少要坐多少次巴士

首先dfs一遍预处理出一个点向上坐$2^k$次巴士能到的最浅点,于是我们能很快地查询一个点往上走到另一个点最少要坐多少次巴士

对于询问$(u,v)$,我们肯定是贪心地坐车,每次坐尽可能远,路径是$u\rightarrow lca_{u,v}\rightarrow v$,我们找到$l_u$表示从$u$开始坐$a$次巴士能到的最浅点,并且再坐一次巴士就能到$lca_{u,v}$,同理坐$b$次巴士到$l_v$

那么如果有线路覆盖$(l_u,l_v)$,那么答案就是$a+b+1$,否则答案是$a+b+2$

考虑离线处理路径覆盖问题,一次dfs即可解决:假设当前节点是某个询问的$l_u$,我们先查询$l_v$的子树和并记下来,然后将所有从$l_u$开始的巴士路线的终点权值$+1$,递归进儿子,最后再查询一次$l_v$的子树和,如果它和之前查询过的值不同,那么说明有巴士线路覆盖$(l_u,l_v)$,否则没有,这个过程用树状数组维护dfs序即可

我写得又慢又丑qwq真实滥用STL

upd:这可能就是dsu on tree?

#include<stdio.h>
#include<vector>
using namespace std;
int h[200010],nex[200010],to[200010],in[200010],ou[200010],dep[200010],fa[200010][18],up[200010][18],M;
void add(int a,int b){
	M++;
	to[M]=b;
	nex[M]=h[a];
	h[a]=M;
}
void dfs(int x){
	M++;
	in[x]=M;
	dep[x]=dep[fa[x][0]]+1;
	for(int i=h[x];i;i=nex[i])dfs(to[i]);
	ou[x]=M;
}
int lca(int x,int y){
	int i;
	if(dep[x]<dep[y])swap(x,y);
	for(i=17;i>=0;i--){
		if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
	}
	if(x==y)return x;
	for(i=17;i>=0;i--){
		if(fa[x][i]!=fa[y][i]){
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return fa[x][0];
}
struct pr{
	int x,y;
	pr(int a=0,int b=0){x=a;y=b;}
};
vector<pr>bg[200010];
void merge(int&x,int y){
	if(x==0||y==0)
		x|=y;
	else if(dep[y]<dep[x])x=y;
}
void dfs2(int x){
	for(pr t:bg[x])merge(up[x][0],t.y);
	for(int i=h[x];i;i=nex[i]){
		dfs2(to[i]);
		merge(up[x][0],up[to[i]][0]);
	}
	if(up[x][0]==x)up[x][0]=0;
}
pr bus(int x,int y){
	pr t;
	int i;
	for(i=17;i>=0;i--){
		if(dep[up[x][i]]>dep[y]){
			x=up[x][i];
			t.y|=1<<i;
		}
	}
	t.x=x;
	return t;
}
int ans[200010],s[200010],n;
vector<pr>ques[200010];
int lowbit(int x){return x&-x;}
int query(int x){
	int res=0;
	while(x){
		res+=s[x];
		x-=lowbit(x);
	}
	return res;
}
int query(int l,int r){
	return query(r)-query(l-1);
}
void modify(int x){
	while(x<=n){
		s[x]++;
		x+=lowbit(x);
	}
}
void dfs3(int x){
	vector<int>v;
	vector<int>::iterator it;
	for(pr t:ques[x])v.push_back(query(in[t.x],ou[t.x]));
	for(pr t:bg[x])modify(in[t.x]);
	for(int i=h[x];i;i=nex[i])dfs3(to[i]);
	it=v.begin();
	for(pr t:ques[x]){
		if(*it==query(in[t.x],ou[t.x]))ans[t.y]++;
		it++;
	}
}
int main(){
	int m,q,i,j,x,y;
	pr tx,ty;
	scanf("%d",&n);
	for(i=2;i<=n;i++){
		scanf("%d",fa[i]);
		add(fa[i][0],i);
	}
	M=0;
	dfs(1);
	for(j=1;j<18;j++){
		for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
	}
	scanf("%d",&m);
	while(m--){
		scanf("%d%d",&x,&y);
		j=lca(x,y);
		bg[x].push_back(pr(y,j));
		bg[y].push_back(pr(x,j));
	}
	dfs2(1);
	for(j=1;j<18;j++){
		for(i=1;i<=n;i++)up[i][j]=up[up[i][j-1]][j-1];
	}
	scanf("%d",&q);
	for(i=1;i<=q;i++){
		scanf("%d%d",&x,&y);
		j=lca(x,y);
		tx=bus(x,j);
		ty=bus(y,j);
		if(x==j){
			if(up[ty.x][0]==0)
				ans[i]=-1;
			else
				ans[i]=ty.y+1;
		}else if(y==j){
			if(up[tx.x][0]==0)
				ans[i]=-1;
			else
				ans[i]=tx.y+1;
		}else{
			if(up[tx.x][0]==0||up[ty.x][0]==0)
				ans[i]=-1;
			else{
				ans[i]=tx.y+ty.y+1;
				ques[tx.x].push_back(pr(ty.x,i));
			}
		}
	}
	dfs3(1);
	for(i=1;i<=q;i++)printf("%d\n",ans[i]);
}

[CF983E]NN country的更多相关文章

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

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

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

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

  3. 【codeforces 983E】NN country

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

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

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

  5. Codeforces983E. NN country

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

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

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

  7. 多校联训 DS 专题

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

  8. Codeforces Round #483 (Div. 1) 简要题解

    来自FallDream的博客,未经允许,请勿转载,谢谢. 为了证明一下我又来更新了,写一篇简要的题解吧. 这场比赛好像有点神奇,E题莫名是道原题,导致有很多选手直接过掉了(Claris 表演24s过题 ...

  9. Abandoned country

    Abandoned country Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

随机推荐

  1. swagger学习2

    转:http://blog.csdn.net/fansunion/article/details/51923720 写的非常好,非常详细,推荐!!!! 最常用的5个注解 @Api:修饰整个类,描述Co ...

  2. HBase并行写机制(mvcc)

    HBase在保证高性能的同时,为用户提供了便于理解的一致性数据模型MVCC (Multiversion Concurrency Control),即多版本并发控制技术,把数据库的行锁与行的多个版本结合 ...

  3. node安装

    由于Node.js平台是在后端运行JavaScript代码,所以,必须首先在本机安装Node环境. 安装Node.js 目前Node.js的最新版本是7.6.x.首先,从Node.js官网下载对应平台 ...

  4. ios上传图片显示方向错误问题

    IOS 上传图片方向显示错误问题 问题描述 在使用苹果手机上传图片的时候,发现传完的图片显示出来方向是错误的,竖着的图片会变成横着显示(少部分安卓手机也存在这个问题) 产生原因 ios 相机加入了方向 ...

  5. iOS 后台运行执行代码(例如定位)

  6. Switf与OC混合开发流程

    看着身边越来越多的小伙伴转入Swift,本人也跟随潮流,转战Swift了~下面是初步写入的一个Swift项目框架. 1.创建项目,这个应该不用说了,语言swift 2.CocoaPods 导入第三方 ...

  7. codevs3304 水果姐逛水果街Ⅰ

    题目描述 Description 水果姐今天心情不错,来到了水果街. 水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样. 学过oi的水果姐迅速发现了 ...

  8. 2017年上海金马五校程序设计竞赛:Problem I : Frog's Jumping (找规律)

    Description There are n lotus leaves floating like a ring on the lake, which are numbered 0, 1, ..., ...

  9. 单源最短路模板_SPFA_Dijkstra(堆优化)_C++

    随手一打就是标准的SPFA,默认1号节点为出发点,当然不用 f 判断是否在队里也可以,只是这样更优化一点 void spfa() { int i,x,k; ;i<=n;i++) { d[i]=o ...

  10. 【跑马灯】纯css3跑马灯demo

    我们写跑马灯一般都是用js控制定时器不断循环产生,但是定时器消耗比较大,特别是程序中很多用到定时器的时候,感觉有的时候比较卡.但是css3样式一般不会.这里主要的思路就是用css3代替js定时器实现一 ...