BZOJ4539: [Hnoi2016]树

复制的树缩点,主席树查k小,毫无技术含量,纯码农题。

#include<bits/stdc++.h>
#define u first
#define v second
#define F lower_bound
#define I (i+j+2>>1)
#define J (i+j>>1)
using namespace std;
int n1,n2,m,n4;
typedef long long ll;
map<ll,int>nu;
const int N=1e5+5;
struct edge{
	int v;edge*s;
}z[N*2];
edge*a=z,*h[N];
void ins(int u,int v){
	edge s={v,h[u]};
	*(h[u]=a++)=s;
}
typedef int arr[N];
arr l,r,b,po,id,d[2],p[2][17];
ll n3,u,v,c[N];
void dfs(int u){
	r[id[l[u]=++n4]=u]=1;
	for(edge*i=h[u];i;i=i->s)
		if(i->v^p[0][0][u]){
			d[0][i->v]=d[0][p[0][0][i->v]=u]+1;
			dfs(i->v);
			r[u]+=r[i->v];
		}
}
typedef struct node*ptr;
struct node{
	ptr i,j;int s;
}e[N][17];
void ins(int i,int j,int s,ptr u,ptr v){
	while(i<j){
		*v=*u;
		if(s>J)u=u->j,v=v->j=v+1,i=J+1;
		else
			++v->s,u=u->i,v=v->i=v+1,j=I-1;
	}
}
int ask(int i,int j,int k,ptr u,ptr v){
	while(i<j){
		int s=v->s-u->s;
		if(k<=s)u=u->i,v=v->i,j=I-1;
		else
			k-=s,u=u->j,v=v->j,i=J+1;
	}
	return i;
}
int lca(int i,int s,int t){
	if(d[i][s]<d[i][t])swap(s,t);
	int k=d[i][s]-d[i][t];
	for(int j=16;~j;--j)
		if(k>>j&1)s=p[i][j][s];
	if(s==t)return s;
	for(int j=16;~j;--j)
		if(p[i][j][s]^p[i][j][t])
			s=p[i][j][s],t=p[i][j][t];
	return p[i][0][s];
}
typedef pair<int,int>vec;
typedef pair<vec,int>tri;
tri ask(ll v){
	typeof(nu.end())j=nu.F(v);
	int s=po[j->v];
	return tri(vec(ask(1,n1,v-j->u+r[s],e[l[s]-1],e[l[s]+r[s]-1]),s),j->v);
}
int ask(int s,int k){
	for(int j=16;~j;--j)
		if(k>>j&1)s=p[1][j][s];
	return s;
}
int main(){
	scanf("%d%d%d",&n1,&n2,&m),++n2;
	for(int i=2;i<=n1;++i)
		scanf("%lld%lld",&u,&v),ins(u,v),ins(v,u);
	dfs(po[nu[n3=n1]=1]=1);
	e[0][0]=(node){e[0],e[0]};
	for(int i=1;i<=n1;++i)
		ins(1,n1,id[i],e[i-1],e[i]);
	for(int i=2;i<=n2;++i){
		scanf("%lld%lld",&u,&v);
		tri s=ask(v);
		d[1][i]=d[1][p[1][0][i]=s.v]+1,c[i]=c[s.v]+d[0][b[i]=s.u.u]-d[0][s.u.v]+1,po[nu[n3+=r[u]]=i]=u;
	}
	for(int i=1;i<17;++i){
		for(int j=1;j<=n1;++j)
			p[0][i][j]=p[0][i-1][p[0][i-1][j]];
		for(int j=2;j<=n2;++j)
			p[1][i][j]=p[1][i-1][p[1][i-1][j]];
	}
	while(m--){
		scanf("%lld%lld",&u,&v);
		tri s1=ask(u),t1=ask(v);
		int l1=lca(1,s1.v,t1.v);
		int s2=s1.u.u,t2=t1.u.u;
		ll l3=0;
		if(s1.v^l1){
			int s3=ask(s1.v,d[1][s1.v]-d[1][l1]-1);
			l3+=d[0][s2]-d[0][s1.u.v]+c[s1.v]-c[s3]+1,s2=b[s3];
		}
		if(t1.v^l1){
			int t3=ask(t1.v,d[1][t1.v]-d[1][l1]-1);
			l3+=d[0][t2]-d[0][t1.u.v]+c[t1.v]-c[t3]+1,t2=b[t3];
		}
		int l2=lca(0,s2,t2);
		l3+=d[0][s2]+d[0][t2]-d[0][l2]*2;
		printf("%lld\n",l3);
	}
}
时间: 2024-09-30 21:11:18

BZOJ4539: [Hnoi2016]树的相关文章

[BZOJ4539][HNOI2016]树(主席树)

4539: [Hnoi2016]树 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 746  Solved: 292[Submit][Status][Discuss] Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过这棵模板树来构建一颗大树.构建过程如下:(1)将模板树复制为初始的大树.(2)以下(2

bzoj4539【HNOI2016】树

4539: [Hnoi2016]树 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 415  Solved: 157 [Submit][Status][Discuss] Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结 点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过这棵模板树来构建一颗大树.构建过 程如下:(1)将模板树复制为初始的大树.(2)

【主席树启发式合并】【P3302】[SDOI2013]森林

Description 给定一个 \(n\) 个节点的森林,有 \(Q\) 次操作,每次要么将森林中某两点联通,保证操作后还是个森林,要么查询两点间权值第 \(k\) 小,保证两点联通.强制在线. Limitation \(1~\leq~n,~Q~\leq~80000\) Solution 考虑有连边还有查询链上第 \(k\) 大,于是要么用 LCT,要么用主席树. 考虑如果用 LCT 的话,并不能快速的维护两点间链的信息(其实感觉在access的时候乱搞一下有希望在多一个 \(\log\) 的

BZOJ 4541: [Hnoi2016]矿区 平面图转对偶图+DFS树

4541: [Hnoi2016]矿区 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 433  Solved: 182[Submit][Status][Discuss] Description 平面上的矿区划分成了若干个开发区域.简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若 干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点 的线段组成.每个开发区域的矿量与该开发区域的面积有关:具

【BZOJ4540】【Hnoi2016】序列 线段树

Claris劲啊!CA劲啊! %%%两位线段树做法传送门在这里和这里 逆向题解时间到: 首先将询问按照终点排序,并且一边从到遍历,不妨设当前遍历到了点,对于之前的每个点,我们维护两个值和.(之后的点的两个值都先设成0) 其中表示从这个点到之间序列A的最小值,而,表示从我们遍历第一个点到当前的所有时刻下的各个历史版本的和.(当遍历的点在这个点之前等于零)(事实上.) 不(很)难发现对于每一个询问,当且仅当时,有.因为 也就是说,如果我们把询问全部离线下来,遍历的时候可以快速更新并且求和,,我们就可

【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改

题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i个元素的值.接下来q行,每行包含两个整数l和r,代表一次询问. 输出 对于每次询问,输出一行,代表询问的答案. 样例输入 5 5 5 2 4 1 3 1 5 1 3 2 4 3 5 2 5 样例输出 28 17 11 11 17 题解 单调栈+离线+扫描线+树状数组区间修改 首先把使用单调栈找出每个

【bzoj】4538: [Hnoi2016]网络

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4538 维护一个数据结构支持对于一颗树的操作,需要支持: 1.对于树上的一条路径上的每个点上放一个值. 2.撤销某次操作的路劲放. 3.查询除了经过这个点的路径的最大值. 往一个路径上丢值相当于往不经过条路径的所有点上丢值. 用一个树链剖分即可维护,对于操作区间取反. 直接查询单点最大值即可. 为了维护单点最大值,线段树中的每一个点对应两个堆,用于维护插入誉删除. 防止爆空间,所以标记永久

bzoj4541【HNOI2016】矿区

4541: [Hnoi2016]矿区 Time Limit: 30 Sec  Memory Limit: 512 MB Submit: 282  Solved: 123 [Submit][Status][Discuss] Description 平面上的矿区划分成了若干个开发区域.简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若 干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点 的线段组成.每个开发区域的矿量与该开发区域的面积有关

HNOI2016 网络 (BZOJ4538)

HNOI2016 Day1 T2 网络 题意:给定一棵树,然后有若干个操作,可以新添加一条从u到v的权值为w的路径,或者将之前的一条路径删掉,动态询问不经过某个点的路径的最大权值 正解:树链剖分+线段树+堆 考场上面打了一个裸裸的树链剖分,连线段树都没套,复杂度是O(m^2 logn)的.当时真是傻了,只要套一个堆就可以AC了...我真傻,真的 首先考虑先树链剖分,然后看怎么处理这三个操作 显然题目要求我们动态维护不经过一个点的最大路径权值,那么我们就考虑用堆 每个线段树的结点里面存两个堆,都是