• 【hiho1065】全图传送


    题目大意:给定一棵 N 个节点的树,点有点权,边有边权,给定 M 个询问,每次询问距离 U 节点不超过 R 的点集中,点权最大的点的编号是多少,若有相同点权,取编号较小的点。

    题解:
    发现是多组询问,而且涉及的问题很难通过子树信息合并来解决。同时距离 U 节点不超过 R 等价于 U 与 V 路径距离不超过 R,可以考虑点分治求解。
    先将询问离线。点分治的过程中维护一个 map<> 表示距离当前分治的根节点距离恰好为 R 的最优点的编号,可以通过在分治过程中遍历一遍子树求得,时间复杂度为 (O(nlogn)),再利用维护得 map 进行构造出距离当前分治中心距离不超过 R 的最优解,即:利用 map 的前一项更新后一项即可。处理出这个之后,再进行遍历子树的操作,对于遍历到的每个点进行查询并更新答案即可。总时间复杂度为 (O(nlog^2n))

    代码如下

    #include <bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    const int maxn=1e5+10;
    typedef long long LL;
    typedef pair<int,int> P;
    
    int n,m,val[maxn],ans[maxn];
    vector<P> q[maxn]; // [r, id]
    struct node{int nxt,to;LL w;}e[maxn<<1];
    int tot=1,head[maxn];
    inline void add_edge(int from,int to,LL w){
    	e[++tot]=node{head[from],to,w},head[from]=tot;
    }
    int rt,sn,sz[maxn],f[maxn];
    LL d[maxn];
    map<LL,int> rec;
    bool vis[maxn];
    void getrt(int u,int fa){
    	sz[u]=1,f[u]=0;
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v==fa||vis[v])continue;
    		getrt(v,u);
    		f[u]=max(f[u],sz[v]);
    		sz[u]+=sz[v];
    	}
    	f[u]=max(f[u],sn-sz[u]);
    	if(!rt||f[u]<f[rt])rt=u;
    }
    
    int better(int x,int y){
    	return val[x]>val[y]||(val[x]==val[y]&&x<y)?x:y;
    }
    void getdis(int u,int fa,LL dist){
    	auto it=rec.find(dist);
    	if(it==rec.end())rec[dist]=u;
    	else rec[dist]=better(rec[dist],u);
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to; LL w=e[i].w;
    		if(v==fa||vis[v])continue;
    		getdis(v,u,dist+w);
    	}
    }
    void update(int u,int fa,LL dist){
    	for(auto p:q[u]){
    		LL r=p.fi; int id=p.se;
    		auto it=rec.upper_bound(r-dist);
    		if(it!=rec.begin()){
    			--it;
    			if(!ans[id])ans[id]=it->se;
    			else ans[id]=better(ans[id],it->se);
    		}
    	}
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to; LL w=e[i].w;
    		if(v==fa||vis[v])continue;
    		update(v,u,dist+w);
    	}
    } 
    void dfs(int u){
    	vis[u]=1;
    	
    	rec.clear();
    	getdis(u,0,0);
    	for(auto x=rec.begin();;x++){
    		auto y=x; ++y;
    		if(y==rec.end())break;
    		y->se=better(x->se,y->se);
    	}
    	update(u,0,0);
    	
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(vis[v])continue;
    		sn=sz[v],rt=0;
    		getrt(v,0);
    		dfs(rt);
    	}
    }
    
    void read_and_parse(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d",&val[i]);
    	for(int i=1;i<n;i++){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add_edge(x,y,z),add_edge(y,x,z);
    	}
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		int u,r;
    		scanf("%d%d",&u,&r);
    		q[u].pb(mp(r,i));
    	}
    }
    void solve(){
    	sn=n,getrt(1,0);
    	dfs(rt);
    	for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
    }
    int main(){
    	read_and_parse();
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    sqlserver json 查询
    分页算法
    context.Response.AddHeader("Access-Control-Allow-Origin", context.Request.Headers["Origin"]); 这个方法是有问题的,AJAX跨域解决方案 在IE11中 context.Request.Headers["Origin"] 这段是获取不到值的。
    NativeWindow 妙用,截取windows消息
    屏蔽浏览器 F12
    linux常用基础命令40条
    shell之正则
    Go语言学习思路与开发软件VScode安装
    shell基础
    docker harbor安装失败
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10990941.html
Copyright © 2020-2023  润新知