首页 > 其他分享 >P3313 [SDOI2014] 旅行

P3313 [SDOI2014] 旅行

时间:2024-04-13 09:02:29浏览次数:19  
标签:旅行 结点 sz ll P3313 SDOI2014 ans MAXN id

题目大意

给定一颗树与一些集合。树上的每个结点一开始都属于一个集合,且都拥有一个点权。定义 \(C_x\) 表示 \(x\) 结点所处的集合。

维护一些操作:

  1. 将结点 \(x\) 到 \(c\) 集合中。
  2. 将结点 \(x\) 的权值改为 \(w\)。
  3. 求出 \(x\) 到 \(y\) 链上所有位于 \(C_x\) 的结点点权最大值。
  4. 求出 \(x\) 到 \(y\) 链上所有位于 \(C_x\) 的结点点权之和。

\(n,q,c\leq 10^5\)

思路

考虑树链剖分。树链剖分可以用来维护链/子树的操作。定义一个结点的重儿子表示它的子儿子的子树大小最大的一个,如果有多个则任取一个。

之后将重儿子移到当前结点的第一个儿子,之后得出新的 \(dfn\) 序。之后的树链剖分就可以找到每一条链上最长的重儿子链,然后对这些链进行维护。可以证明每一次经过的链是 \(\log n\) 级别的,之后用线段树什么的维护序列即可。

对于本题,我们可以建 \(c\) 颗动态开点线段树去维护每一个集合的信息。如果 \(C_x\) 不属于当前的线段树直接把对应位置赋值为 \(0\) 即可。

时间复杂度 \(O(n\log_2^2 n)\),空间复杂度 \(O(n\log n)\)。

代码

#include<bits/stdc++.h>
#define lc(u) t[u].l
#define rc(u) t[u].r
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
ll n,q;
ll w[MAXN],c[MAXN]; 
vector<ll>adj[MAXN];
ll tot,sz[MAXN],dfn[MAXN],id[MAXN],cs[MAXN],fa[MAXN],dep[MAXN],hs[MAXN];
void dfs(ll u,ll f,ll d){
	dep[u]=d;
	fa[u]=f;
	sz[u]=1;
	for(auto v:adj[u]){
		if(v==f){
			continue;
		}
		dfs(v,u,d+1);
		sz[u]+=sz[v];
		if(!hs[u]||sz[hs[u]]<sz[v]){
			hs[u]=v;
		}
	}
}
void dfs_divide(ll u,ll start){
	cs[u]=start;
	dfn[++tot]=u;
	id[u]=tot;
	if(hs[u]==0){
		return;
	} 
	dfs_divide(hs[u],start);
	for(auto v:adj[u]){
		if(v==fa[u]||v==hs[u]){
			continue;
		}
		dfs_divide(v,v);
	}
}
struct node{
	ll u,val,ma,l,r;
}t[10000000];
ll nt=MAXN;
void push_up(ll u){
	t[u].val=t[lc(u)].val+t[rc(u)].val;
	t[u].ma=max(t[lc(u)].ma,t[rc(u)].ma);
}
void change(ll &u,ll l,ll r,ll pos,ll x){
	if(!u){
		u=++nt; 
	} 
	if(l==r){
		t[u].val=t[u].ma=x;
		return;
	}
	ll mid=(l+r)>>1;
	if(pos<=mid){
		change(lc(u),l,mid,pos,x);
	}else{
		change(rc(u),mid+1,r,pos,x);
	}
	push_up(u);
}
ll query1(ll u,ll l,ll r,ll ql,ll qr){
	if(!u){
		return 0;
	}
	if(ql<=l&&r<=qr){
		return t[u].val;
	} 
	ll mid=(l+r)>>1,ans=0;
	if(ql<=mid){
		ans+=query1(lc(u),l,mid,ql,qr); 
	}
	if(mid+1<=qr){
		ans+=query1(rc(u),mid+1,r,ql,qr);
	}
	return ans;
}
ll query2(ll u,ll l,ll r,ll ql,ll qr){
	if(!u){
		return 0;
	}
	if(ql<=l&&r<=qr){
		return t[u].ma;
	} 
	ll mid=(l+r)>>1,ans=0;
	if(ql<=mid){
		ans=query2(lc(u),l,mid,ql,qr); 
	}
	if(mid+1<=qr){
		ans=max(ans,query2(rc(u),mid+1,r,ql,qr));
	}
	return ans;
}
ll qs(ll u,ll v,ll C){
	ll ans=0;
	while(cs[u]!=cs[v]){
		if(dep[cs[u]]<dep[cs[v]]){
			swap(u,v);
		}
		ans+=query1(C,1,n,id[cs[u]],id[u]);
		u=fa[cs[u]];
	}
	if(dep[u]>dep[v]){
		swap(u,v); 
	} 
	return ans+query1(C,1,n,id[u],id[v]);
}
ll qm(ll u,ll v,ll C){
	ll ans=0;
	while(cs[u]!=cs[v]){
		if(dep[cs[u]]<dep[cs[v]]){
			swap(u,v);
		}
		ans=max(ans,query2(C,1,n,id[cs[u]],id[u]));
		u=fa[cs[u]];
	}
	if(dep[u]>dep[v]){
		swap(u,v); 
	} 
	return max(ans,query2(C,1,n,id[u],id[v]));
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>q;
	for(int i=1;i<=n;++i){
		cin>>w[i]>>c[i];
	} 
	for(int i=1;i<n;++i){
		ll x,y;
		cin>>x>>y;
		adj[x].push_back(y);
		adj[y].push_back(x); 
	}
	dfs(1,0,1);
	dfs_divide(1,1);
	for(int i=1;i<=n;++i){
		change(c[i],1,n,id[i],w[i]);
	}
	while(q--){
		string op;
		cin>>op;
		if(op=="CC"){
			ll x,nc;
			cin>>x>>nc;
			change(c[x],1,n,id[x],0);
			c[x]=nc;
			change(c[x],1,n,id[x],w[x]);
		}else if(op=="CW"){
			ll x,nw;
			cin>>x>>nw;
			w[x]=nw;
			change(c[x],1,n,id[x],w[x]);
		}else if(op=="QS"){
			ll x,y;
			cin>>x>>y;
			cout<<qs(x,y,c[x])<<endl;
		}else if(op=="QM"){
			ll x,y;
			cin>>x>>y;
			cout<<qm(x,y,c[x])<<endl;
		}
	}
	return 0;
}

标签:旅行,结点,sz,ll,P3313,SDOI2014,ans,MAXN,id
From: https://www.cnblogs.com/tanghg/p/18132473/solution-p3313

相关文章

  • 2023蓝桥杯 java A组 小蓝的旅行计划
    最小堆(优先队列)和区间树(线段树,红黑树)的结合java中有自己实现这两种数据结构的对象(1)最小堆(优先队列)PriorityQueue<int[]>minHeap=newPriorityQueue<>(newComparator<int[]>(){//int[]三个元素第一个cost第二个lim第三个tag @Override publicintcompare(int......
  • 去哪儿完成鸿蒙原生应用Beta版本开发,带来一站式在线旅行体验
    近日,国内领先的在线旅行服务平台去哪儿宣布完成鸿蒙原生应用Beta版本开发,成为旅行行业中首批完成Beta版开发的应用之一,该版本已经实现了机票预订、支付、服务等功能,将为用户提供更为便捷、智能的旅行体验。这不仅为旅行行业树立了榜样,也为整个互联网行业在鸿蒙系统上的发展提供了......
  • <商务世界>《第28课 商务旅行的注意事项》
    1选择人气旺的酒店酒店找一个旺气的地方。1是干净、整洁是最重要的。2是在选择酒店的时候尽量选择闹市,人口要集中的地方,这样入住率有保证,人多气场旺不至于发生一些灵异事件。而且人少屋多,也会让我们没有安全感。2避免无窗房酒店住房要尽量避免选择没有窗户或者窗户过小......
  • 「CTSC2010」星际旅行
    换根dp#贪心由限制\(h_i\)大于点的度数,最终回到根的答案必然是经过每个节点的根的答案可以\(\mathcal{O}(n)\)的算出考虑如何换根,分\(3\)种情况(假设现在由\(rt\rightarrowx\))当前的\(rt\)有多余的出边,那么用这个出边走到\(x\),\(ans+1\)当前\(rt\)没有多余......
  • 十九 731. 毕业旅行问题 (状态压缩DP)
    731.毕业旅行问题(状态压缩DP)思路:使用状态压缩DP,dp[i][j]中i表示状态(二进制表示),j表示最后所在城市。算法时间复杂度是O(2n*n2),需要优化掉没有访问过1号城市的状态和无效状态。importjava.util.*;publicclassMain{privatestaticintn;privatestaticint......
  • 【附源码】java毕业设计生活旅行分享网站的设计与实现
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着经济的发展和生活水平的提高,旅行已经成为现代人休闲放松的一种重要方式。人们不仅希望在旅行中体验不同的文化、风光和生活,还愿意通过互联网与他人分......
  • TSP旅行商问题——SA模拟退火算法,SA+GA组合算法(代码解释)
    SA代码直接用就行,成功率极高importrandomimportnumpyasnpimportmatplotlib.pyplotasplt#randomlygeneratethemapwithconstraintof[-100,100]defgen_cities(city_num,random_state=True):ifrandom_state:cities=(np.random.uniform(0......
  • 解决[TSP旅行商]问题,请列出[4]个可以用[Python]编程的优化路径算法,展开写出这[4]个算
    TSP(旅行商问题)是一个经典的组合优化问题,其目标是找到访问所有城市并返回起点的最短可能路线。在Python中,有多种算法可以用来解决TSP问题,以下是四个常用的算法及其编程难度级别、时间复杂度和所需的库:回溯法(Backtracking)编程难度级别:中等时间复杂度:指数级,因为需要遍历所有......
  • 基于携程旅行平台自由行的旅游线路管理信息系统(JSP+java+springmvc+mysql+MyBatis)
    本项目包含程序+源码+数据库+LW+调试部署环境,文末可获取一份本项目的java源码和数据库参考。项目文件图项目介绍随着个性化旅游需求的增加,自由行成为越来越多旅行者的选择。基于携程旅行平台的自由行旅游线路管理信息系统,旨在为用户提供更加灵活、个性化的旅游规划服务。系......
  • 杭电OJ 2066 一个人的旅行
    一个人的旅行考查图论中的单源最短路径问题,首先图的存储方式,前面说过在实际程序中一般用邻接表,为每一个顶点都分配一个单链表(向量)。由于这里顶点的总个数并不确定,用visit数组在集合T中遍历寻找下一个用来松弛的顶点,这一方式不太合适,所以这里我用优先队列,每次弹出距离起始点距离......