首页 > 其他分享 >Gym104076L Tree Distance

Gym104076L Tree Distance

时间:2023-03-29 09:12:00浏览次数:53  
标签:Gym104076L ch Distance int siz Tree tp st put

Gym104076L Tree Distance

题目链接

\(\text{difficulty}={4,2.5}\)。

\(\text{tags}=点分治,扫描线\)。

没见过确实想不到。

由于查询是区间对区间,分块等数据结构并不好直接维护。考虑找一些性质,如果两个点 \(l,r(l <r)\) 的距离大于等于被其包含的两个点 \(i,j(l<i<j<r)\),那么 \(l,r\) 一定不会成为答案。

那么我们尝试找到所有可能成为答案的点对。考虑点分治,设当前分治中心为 \(x\)。对于其中一个子树中的点 \(a\),我们希望找到一些 \(b\) 满足 \(\text{dis}(a,x)\le \text{dis}(b,x)\) 并且 \(a,b\) 不在同一个子树内。

考虑如果有多个点满足条件,其中两个为 \(b,c\),我们考虑 \(b<c<a\) 的情况,那么根据 \(b,c\) 的条件显然有 \(\text{dis}(b,c)\le \text{dis}(b,a)\),所以保留 \((b,a)\) 是没有意义的。对于 \(a<c<b\) 的情况同理。

那么实际上需要对于每个 \(a\) 找到与其不在同一个子树内并且 \(\text{dis}(x,b)\le \text{dis}(x,a)\) 的前驱 \(b\) 和后继 \(b\)。进一步发现不在同一个子树的限制意义不大,因为如果找到了同一子树的点 \(b\),那么 \(b\) 一定比 \(a\) 更优。

那么我们只需要将分治中心 \(x\) 内的所有点按照深度排序,然后正着做一遍单调栈求出每个点的前驱 \(b\),再反着做一遍单调栈求出每个点的后继 \(b\) 即可找到所有关键点。

由于每一层每个 \(a\) 只会找到两个 \(b\),所以总点对个数是 \(\mathcal{O}(n \log n)\) 级别的。

接下来就是一个简单的二维数点,将点对 \((a,b)(a<b)\) 挂在 \(b\) 上,将询问 \([l,r]\) 挂在 \(r\) 上,然后从左往右扫,每次单点插入,求后缀 \(\max\),使用树状数组维护即可。

总时间复杂度 \(\mathcal{O}(n \log^2 n+q\log n)\)。

code
#include<bits/stdc++.h>
using namespace std;
namespace IO{
	template<typename T>inline bool read(T &x){
		x=0;
		char ch=getchar();
		bool flag=0,ret=0;
		while(ch<'0'||ch>'9') flag=flag||(ch=='-'),ch=getchar();
		while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(),ret=1;
		x=flag?-x:x;
        return ret;
	}
	template<typename T,typename ...Args>inline bool read(T& a,Args& ...args){
	    return read(a)&&read(args...);
	}
	template<typename T>void prt(T x){
		if(x>9) prt(x/10);
		putchar(x%10+'0');
	}
	template<typename T>inline void put(T x){
		if(x<0) putchar('-'),x=-x;
		prt(x);
	}
	template<typename T>inline void put(char ch,T x){
		if(x<0) putchar('-'),x=-x;
		prt(x);
		putchar(ch);
	}
	template<typename T,typename ...Args>inline void put(T a,Args ...args){
	    put(a);
		put(args...);
	}
	template<typename T,typename ...Args>inline void put(const char ch,T a,Args ...args){
	    put(ch,a);
		put(ch,args...);
	}
	inline void put(string s){
		for(int i=0,sz=s.length();i<sz;i++) putchar(s[i]);
	}
	inline void put(const char* s){
		for(int i=0,sz=strlen(s);i<sz;i++) putchar(s[i]);
	}
}
using namespace IO;
#define N 200005
#define ll long long
int n,q,head[N],cnt;
ll ans[N*5];
struct edge{
	int v,nxt,val;
}e[N<<1]; 
inline void add(int u,int v,int w){
	e[++cnt]=(edge){v,head[u],w},head[u]=cnt;
}
vector<pair<int,ll> >que[N],ins[N],p;
bool vis[N];
int st[N],tp;
inline int get_siz(int x,int fa){
	if(vis[x]) return 0;
	int siz=1;
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].v!=fa) siz+=get_siz(e[i].v,x);
	return siz;
}
inline int get_wc(int x,int fa,int sum,int &wc){
	if(vis[x]) return 0;
	int siz=1,ms=0;
	for(int i=head[x],t;i;i=e[i].nxt)
		if(e[i].v!=fa) t=get_wc(e[i].v,x,sum,wc),siz+=t,ms=max(ms,t);
	if(max(ms,sum-siz)<=sum/2) wc=x;
	return siz;
}
inline void get_dist(int x,int fa,ll pre){
	p.emplace_back(x,pre);
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].v!=fa&&!vis[e[i].v]) get_dist(e[i].v,x,pre+e[i].val);
}
inline void solve(int x){
	if(vis[x]) return;
	p.clear();
	get_wc(x,0,get_siz(x,0),x),vis[x]=1;
	get_dist(x,0,0),sort(p.begin(),p.end());
	for(int i=0,tp=0;i<p.size();i++){
		while(tp&&p[st[tp]].second>p[i].second) tp--;
		if(tp) ins[p[i].first].emplace_back(p[st[tp]].first,p[i].second+p[st[tp]].second);
		st[++tp]=i;
	}
	for(int i=p.size()-1,tp=0;~i;i--){
		while(tp&&p[st[tp]].second>p[i].second) tp--;
		if(tp) ins[p[st[tp]].first].emplace_back(p[i].first,p[i].second+p[st[tp]].second);
		st[++tp]=i;
	}
	for(int i=head[x];i;i=e[i].nxt) solve(e[i].v);
}
struct BIT{
	ll c[N];
	BIT(){memset(c,0x3f,sizeof(c));}
	#define lowbit(x) (x&-x)
	inline void update(int x,ll v){
		for(;x;x^=lowbit(x)) c[x]=min(c[x],v);
	}
	inline ll query(int x){
		ll res=0x3f3f3f3f3f3f3f3f;
		for(;x<=n;x+=lowbit(x)) res=min(res,c[x]);
		return res;
	}
	#undef lowbit
}B;
int main(){
	read(n);
	for(int i=1,u,v,w;i<n;i++)
		read(u,v,w),add(u,v,w),add(v,u,w);
	solve(1),read(q);
	for(int i=1,l,r;i<=q;i++)
		read(l,r),que[r].emplace_back(l,i);
	for(int i=1;i<=n;i++){
		for(auto tmp:ins[i]) B.update(tmp.first,tmp.second);
		for(auto tmp:que[i]) ans[tmp.second]=B.query(tmp.first);
	}
	for(int i=1;i<=q;i++) put('\n',ans[i]>=0x3f3f3f3f3f3f3f3f?-1:ans[i]);
	return 0;
}

标签:Gym104076L,ch,Distance,int,siz,Tree,tp,st,put
From: https://www.cnblogs.com/fzj2007/p/17267508.html

相关文章

  • TreeMap特性
    TreeMap可以实现的数据结构具有平衡搜索二叉树的设计:AVL,SB树,红黑树常规外设计:跳表时间复杂度都是:Log(N)区别只有常数级别的TreeMap<Integer,String>treeMap......
  • ztree 右键菜单功能
    https://blog.csdn.net/weixin_42217154/article/details/107681018右键菜单的功能是这样来的,首先设计一个菜单,用于右击显示;菜单上放置一些元素(控件),以供我们选择;然后就是......
  • WPF TreeView控件根据数据内容跳转到指定节点
    1、问题描述一般,当我们需要展开TreeView控件的某一节点时,可以在TreeView控件的TreeViewItem所绑定的数据结构上增加一个bool属性,然后与TreeViewItem的IsExpand属性相绑定,......
  • Paper Reading: PS-Tree A piecewise symbolic regression tree
    目录研究动机文章贡献分段符号回归树个体表示特征分区初始化自适应决策树重建多目标训练PS-Tree算法流程生成算子适应度评估选择算子实验分析数据集PS-Tree实验设置消融......
  • js树形控件—zTree使用
    https://blog.csdn.net/qq_35934094/article/details/80852989https://www.cnblogs.com/leechenxiang/p/5952959.htmlhttps://www.jianshu.com/p/99d24aab74a5详见官网:h......
  • 算法杂货铺——分类算法之决策树(Decision tree)
    3.1、摘要     在前面两篇文章中,分别介绍和讨论了朴素贝叶斯分类与贝叶斯网络两种分类算法。这两种算法都以贝叶斯定理为基础,可以对分类及决策问题进行概率推断。在这......
  • CSCI-1200 Simplified B+ Trees
    CSCI-1200DataStructures—Spring2023Homework8—SimplifiedB+TreesInthisassignmentwewillbeimplementingapartialandmodifiedversionofB+trees.......
  • git解决error: The following untracked working tree files would be overwritten by
    在IDEA中进行分支切换时,出现如此错误,导致无法正常切换:error:Thefollowinguntrackedworkingtreefileswouldbeoverwrittenbycheckout通过错误提示可知,是由于一些un......
  • 获取tree跨行跨列
      获取tree跨行跨列 functiongetColspan(column){letcolspan=0constchildren=column.children||[]for(leti=0;i<children.length;i++)......
  • 平衡二叉树 -(avltree)
    AVL树简介AVL树的名字来源于发明作者G.M.Adelson-Velsky和E.M. Landis的缩写。AVL树是最先发明的自平衡二叉查找树(Self-BalancingBinarySearchTree,简称平衡二叉树......