[gym104076][CCPC2022济南站L] Tree Distance

You are given an unrooted weighted tree \(T\) with vertices \(1,2,…,n\). Please answer some queries.

We define \(dist(i,j)\) as the distance between vertex i and vertex \(j\) in \(T\).

For each query, you are given two integers \(l,r\). Please answer the value of

\[\min\limits_{l\le i<j\le r}dis(i,j) \]

Input

The first line contains one integer \(n (1≤n≤2×10^5)\), the number of vertices in the tree.

Each of the next n−1 lines describes an edge of the tree. Edge i is denoted by three integers \(a_i,b_i,w_i (1≤a_i,b_i≤n,1≤w_i≤10^9)\), the labels of vertices it connects and its weight.

Then one line contains one integer \(q (1≤q≤10^6)\), the number of queries.

Each of the following q lines contains two integers \(l,r\) \((1≤l≤r≤n)\) describing a query.

It is guaranteed that the given edges form a tree.

Output

For each query, output the answer in one line. If there is no \(i,j\) such that \(1≤i<j≤r\), the answer is \(−1\).

距离问题,考虑点分治

对于一个目前的根 \(x\) 以及若干个连通块中的点,可以把所有点按照编号排序。此时考虑把一些点对设为可能成为答案的点对。

如果此时有 \(i,j,k\) 满足 \(i<j<k\)\(dep_i\ge dep_j,dep_k\),那么 \((i,k)\) 一定不是可以满足要求的点对。因为如果区间包含了 \((i,k)\),一定包含了 \((j,k)\),同时 \(dep_i+dep_j>dep_j+dep_k\)。所以我们不用理他。

由此,我们可以点分治完,对于每个连通块里的点 \(i\),按照编号排序,然后用单调栈找到左右最靠近他的 \(dep\) 小于等于 他的第一个数 \(lst_i,nxt_i\)。容易发现最后得到可能为答案的点对最多只有 \(O(nlogn)\) 个。

把点对按照大的那个数排序,然后扫描线,需要支持单点改,求后缀最小值。树状数组维护即可。对于一个点对 \((l,r,dist(l,r))\),可以当扫到 \(r\) 时把 \(l\)\(dist(l,r)\) 去最小值。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+5;
const LL INF=1e18;
int n,v[N],hd[N],m,rt,k,q,f[N<<3],sz[N],mx,e_num,nwp,st[N],tp,nxt[N],lst[N];
LL tr[N],ans[N<<3];
struct edge{
	int v,nxt,w;
}e[N<<1];
struct node{
	int l,r;
	LL dep;
	bool operator<(const node&n)const{
		return r<n.r;
	}
}p[N<<6];
struct dian{
	int x;
	LL dep;
	bool operator<(const dian&d)const{
		return x<d.x;
	}
}a[N];
vector<int>g[N];
void add_edge(int u,int v,int w)
{
	e[++e_num]=(edge){v,hd[u],w};
	hd[u]=e_num;
}
void sou(int x,LL dep,int f)
{
	a[++m]=(dian){x,dep};
	for(int j=hd[x];j;j=e[j].nxt)
		if(!v[e[j].v]&&e[j].v^f)
			sou(e[j].v,dep+e[j].w,x);
}
void suo(int x,int f,int n)
{
	int cnt=0;
	sz[x]=1;
	for(int i=hd[x];i;i=e[i].nxt)
	{
		if(!v[e[i].v]&&e[i].v^f)
		{
			suo(e[i].v,x,n);
			sz[x]+=sz[e[i].v];
			cnt=max(cnt,sz[e[i].v]);
		}
	}
	cnt=max(cnt,n-sz[x]);
	if(cnt<mx)
		mx=cnt,rt=x;
}
int findrt(int x,int n)
{
	rt=0,mx=2000000000;
	suo(x,0,n);
//	printf("%d\n",mx);
	return rt;
}
void tosz(int x,int f)
{
	sz[x]=1;
	for(int i=hd[x];i;i=e[i].nxt)
	{
		if(!v[e[i].v]&&e[i].v^f)
		{
			tosz(e[i].v,x);
			sz[x]+=sz[e[i].v];
		}
	}
}
void dfs(int x)
{
//	printf("hjhyyds:%d\n",x);
	sou(x,m=0,0);
	tosz(rt,0);
	sort(a+1,a+m+1);
//	for(int i=1;i<=m;i++)
//		printf("%d %d\n",a[i].x,a[i].dep);
	tp=0;
//	if(x==5)
//		puts("chtyyds:");
	for(int i=1;i<=m;i++)
	{
		while(tp&&a[st[tp]].dep>=a[i].dep)
			nxt[st[tp--]]=i;
		st[++tp]=i;
//		if(x==5)
//		{
//			for(int j=1;j<=tp;j++)
//				printf("%d ",st[j]);
//			puts("");
//		}
	}
//	puts("qzmyyds");
	tp=0;
	for(int i=m;i>=1;i--)
	{
		while(tp&&a[st[tp]].dep>=a[i].dep)
			lst[st[tp--]]=i;
		st[++tp]=i;
	}
	for(int i=1;i<=m;i++)
	{
		if(lst[i])
			p[++k]=(node){a[lst[i]].x,a[i].x,a[lst[i]].dep+a[i].dep} ;
		if(nxt[i])
			p[++k]=(node){a[i].x,a[nxt[i]].x,a[nxt[i]].dep+a[i].dep};
		lst[i]=nxt[i]=0;
	}
//	if(x==5)
//	{
//		for(int i=1;i<=m;++i)
//			printf("%d %d\n",a[i].x,a[i].dep);
//		printf("xzd%%%:%d\n",nxt[1]);
//	}
	v[x]=1;
	for(int i=hd[x];i;i=e[i].nxt)
		if(!v[e[i].v])
			dfs(findrt(e[i].v,sz[e[i].v]));
}
void update(int x,LL y)
{
//	printf("%d %lld\n",x,y) ;
	for(;x<=n;x+=x&-x)
		tr[x]=min(tr[x],y);
}
LL query(int x)
{
//	printf("qu:%d\n",x);
	LL ret=1e18;
	for(;x;x-=x&-x)
		ret=min(ret,tr[x]);
//	printf("%lld\n",ret);
	return ret;
}
signed main()
{
	memset(tr,0x7f,sizeof(tr));
	scanf("%d",&n);
	for(int i=1,u,v,w;i<n;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		add_edge(u,v,w);
		add_edge(v,u,w);
	}
	scanf("%d",&q);
	for(int i=1,y;i<=q;i++)
	{
		scanf("%d%d",f+i,&y);
		g[y].push_back(i);
	}
	dfs(findrt(1,n));
	sort(p+1,p+k+1);
//	for(int i=1;i<=k;i++)
//		printf("%d %d %lld\n",p[i].l,p[i].r,p[i].dep);
	nwp=0;
	for(int i=1;i<=n;i++)
	{
		while(nwp^k&&p[nwp+1].r==i)
		{
			++nwp;
			update(n-p[nwp].l+1,p[nwp].dep);
		}
		for(int j=0;j<g[i].size();j++)
			ans[g[i][j]]=query(n-f[g[i][j]]+1);
	}
	for(int i=1;i<=q;i++)
		printf(ans[i]==INF? "-1\n":"%lld\n",ans[i]);
}
posted @ 2023-02-07 20:29  灰鲭鲨  阅读(65)  评论(0编辑  收藏  举报