首页 > 其他分享 >P9481 [NOI2023] 贸易 题解

P9481 [NOI2023] 贸易 题解

时间:2023-08-01 14:48:34浏览次数:33  
标签:siz 题解 ll P9481 dis NOI2023 lca include mod

题目链接

题目要求我们求出任意两点间最短路径之和,由于图比较特殊,除树边外只有祖先到其子树内的边,我们首先考虑最短路径有没有什么特殊性质。

注意到两点之间的最短路分为一下三种:

  1. 节点到其祖先的最短路:直接沿着树边向上走即可,否则一定会走多余的边,不是最优。

  2. 节点到其子树的最短路:此时最短路一定形如沿着树边走若干条边,再走一条非树边,走若干条树边如此交替进行,当然此处也可以连续走非树边。

  3. 两个节点没有祖先孩子关系的最短路:如果此时要从 \(u\) 点走到 \(v\) 点,由于图中没有横叉边,\(u\) 点必须要走到 \(\operatorname{lca}(u,v)\),否则一定无法通过非树边到 \(v\) 点,之后转为为从 \(\operatorname{lca}(u,v)\) 到 \(v\) 的第二类最短路。

这三条最短路都会经过 \(\operatorname{lca}(u,v)\),由于其唯一性,考虑枚举最近公共祖先统计答案,第二类是方便统计的,而此时第一类也已经被处理了,我们把第三类分为两部分:从 \(u\) 到 \(\operatorname{lca}(u,v)\) 和 从 \(\operatorname{lca}(u,v)\) 到 \(v\)。

第一段通过预处理即可解决,对于每个枚举到的 \(\operatorname{lca}\),由于树高是 \(\log\) 的,第二段路径所牵扯到的节点数也不会超过 \(N\log N\) 个,因此可以直接建反图暴力跑最短路统计,之后模仿点分治计算一遍即可。

代码中我对于每个 \(\operatorname{lca}\) 的子节点正序倒序分别枚举了一次,枚举到每颗子树时累加前面的子树走前半段,这颗子树走后半段的答案,即可保证不重不漏。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector> 
#include<queue>
#define ll long long
#define N 700005
using namespace std;
const ll mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll tot,dsum[N],dfn[N],ri[N],val[N],dis[N],vis[N],dep[N];
ll bel[N],siz[N],ans,ttp[N],sta[N],p,ct[N];
struct graph{
	ll e,head[N],to[N],nex[N],edg[N];
	void add(ll u,ll v,ll w){
		to[++e]=v;nex[e]=head[u];head[u]=e;edg[e]=w;
	}
	void clear(){
		for(ll i=1;i<=e;i++)head[i]=nex[i]=edg[i]=to[i]=0;
		e=0;
	}
}T,G;
struct edg{
	ll u,v,w;
};
struct Node{
	ll v,val;
	bool operator <(const Node &x)const{
		return val>x.val;
	}
};
void adj(ll &x){
	x=(((x%mod)+mod)%mod);
}
priority_queue<Node> q;
vector<edg> E[N];
void dfs(ll x){
	dfn[x]=++tot;bel[tot]=x;siz[x]=1;
	for(ll i=T.head[x];i;i=T.nex[i]){
		ll v=T.to[i],w=T.edg[i];dep[v]=dep[x]+w;adj(dep[v]);dfs(v);
		dsum[x]+=w*siz[v]+dsum[v];dsum[x]%=mod;
		siz[x]+=siz[v];
	}
	ri[x]=tot;
}
void dij(ll s){
	q.push((Node){s,0});dis[s]=0;
	while(q.size()){
		ll x=q.top().v;q.pop();if(vis[x]) continue;
		vis[x]++;
		for(ll i=G.head[x];i;i=G.nex[i]){
			ll v=G.to[i],w=G.edg[i];
			if(dis[v]>dis[x]+w){
				dis[v]=dis[x]+w;
				q.push((Node){v,dis[v]});
			}
		}
	}
}
void dfs2(ll x){
	G.clear();
	for(ll i=dfn[x];i<=ri[x];i++){
		dis[i]=inf;vis[i]=0;ans+=dep[bel[i]]-dep[x];adj(ans);
		for(ll j=0;j<E[bel[i]].size();j++){
			G.add(dfn[E[bel[i]][j].u],dfn[E[bel[i]][j].v],E[bel[i]][j].w);
		}
		G.add(dfn[bel[i]],dfn[bel[i]/2],val[bel[i]]);
	}
	ll tmp=x,tmp2=x/2,sumdis=0,sumsiz=1,cnt=0,tp=0;
	while(tmp2){
		G.add(dfn[tmp],dfn[tmp2],val[tmp]);
		vis[dfn[tmp]]=0;dis[dfn[tmp]]=inf;tmp=tmp2;tmp2/=2;
	}
	vis[1]=0;dis[1]=inf;dij(dfn[x]);tmp=x;p=0;
	for(ll i=T.head[x];i;i=T.nex[i]){
		sta[++p]=i;ll v=T.to[i];tp=0;cnt=0;
		for(ll j=dfn[v];j<=ri[v];j++){
			if(dis[j]!=inf){
				tp+=dis[j];adj(tp);cnt++;
			}
		}
		ttp[v]=tp;ct[v]=cnt;
		ans+=((sumsiz*tp)%mod)+((cnt*sumdis)%mod);adj(ans);
		sumsiz+=siz[v];adj(sumsiz);
		sumdis+=dsum[v]+((T.edg[i]*siz[v])%mod);adj(sumdis);
	}
	sumsiz=sumdis=0;
	for(ll i=p;i>=1;i--){
		ll j=sta[i],v=T.to[j];tp=ttp[v];cnt=ct[v];
		ans+=((sumsiz*tp)%mod)+((cnt*sumdis)%mod);adj(ans);
		sumsiz+=siz[v];adj(sumsiz);
		sumdis+=dsum[v]+((T.edg[j]*siz[v])%mod);adj(sumdis);
	}
	for(ll i=dfn[x];i<=ri[x];i++)G.head[i]=dis[i]=0;
	while(tmp){G.head[dfn[tmp]]=0;dis[dfn[tmp]]=0;tmp/=2;}
	for(ll i=T.head[x];i;i=T.nex[i])dfs2(T.to[i]);
}
ll read(){
	ll x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
int main(){
	ll n,m,u,v,w;n=read();m=read();n=(1<<n)-1;
	for(ll i=2;i<=n;i++){cin>>w;T.add((i/2),i,w);val[i]=w;}
	for(ll i=1;i<=m;i++){
		u=read();v=read();w=read();
		E[v].push_back((edg){u,v,w});
	}
	dfs(1);dfs2(1);
	cout<<ans;
}

标签:siz,题解,ll,P9481,dis,NOI2023,lca,include,mod
From: https://www.cnblogs.com/eastcloud/p/17596401.html

相关文章

  • NOI2023 后记
    Day1被找规律随机区分\(35\)分。Day2以我现有的水平已经无力回天了,d2T3却还挂了\(35\)分。连队线的边都没碰到,只混到了\(100\)多名的Ag。我不愿回忆这场考试的任何细节,知道寄了就行了。分数是从低往高排的。nfls的众人中,我是第一个上去的。为什么在公布Ag名单时,......
  • 题解 [NOI2020] 命运
    Link题意给定一棵\(n\)个节点的有根树和\(m\)条祖先到后代的链。问有多少种把边权设置为\(0\)或\(1\)的方案使得每条链上至少有一条边是\(1\)。答案对\(998244353\)取模。\(1\leqn,m\leq5\times10^5\)题解我们将链的下端称为限制的起点。容易发现,对于同一......
  • 国标GB28181视频平台LntonGBS(源码版)国标平台迁移服务器后无法启动的问题解决方案
    国标视频云服务LntonGBS支持设备/平台通过国标GB28181协议注册接入,并能实现视频的实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。平台部署简单、可拓展性强,支持将接入的视频流进行全终端、全平台分发,分发的视频流包括RTSP、RTMP、FLV、HLS、WebRTC等格......
  • 【游记】NOI2023
    前情提要:HE春测+省选rk24,D类选手。前言之前省选游记好像说目标是拿到D类名额+省内高一前\(5\),虽然做到了但是D1T2没分析出很显然的树上做法、D1T3没有想线段树分治以及D2T2选择二分图建模而不是二元组连边都是相当降智操作。结果是导致清北营不过审。中途\(6\)月......
  • NOI2023游记
    想了很久,还是决定写退役记,全都要靠回忆所以应该会漏不少细节。因为已经退役,比赛过程写的比较少,看个乐就行。7.2~7.212号提前到了成都七中,打了两周多的模拟赛。基本都是垫底的,题也补的很少。感觉状态有点差的。保持手感完全靠和学弟duel,学弟好强。7.22报到日。上午大概10......
  • 洛谷 U321190 麻将 加强加强版 题解
    Description给定一副\(k\)张牌的麻将牌,求能「听」哪些牌。对于所有数据,\(1\leqk\leq2\times10^5\)。link:https://www.luogu.com.cn/problem/U321190Solution算法零枚举「听」的牌,用状压DP或者贪心判断。时间复杂度\(\mathcal{O}(2^n\text{poly}(n))\)或\(\mathca......
  • [NOI2023] 深搜
    和考试的时候思路差不多。首先考虑钦定一部分关键点是合法的根,带上容斥系数。对于一条非树边,要求其在任何一个钦定点作为根的时候都不是横叉边。具体而言,对于一个钦定点集合,我们建出钦定点集合的虚树,那么符合条件的非树边有如下几类:不妨先考虑特殊性质\(B\),没有横叉边的情......
  • DVWA靶场搭建过程 & 遇到的问题解决(apache标红、无法跳转等等)
    问题会在最后汇总解答第一步准备工作首先需要搭建PHP环境和获取DVWA源代码搭建PHP环境:搜索phpstudy→鼠标移动至windows版→点击phpstudy客户端→下滑,下载phpStudy2018Windows版本【注意,选择下载路径必须全英文】→获取到一个安装包,暂时不用解压。获取DVWA源代码:输入网站......
  • [NOI2023] 字符串
    对于给出的串\(S\),将其拓展成\(S+\)特殊字符\(+rev(S)\),求出其后缀数组。那么对于一个子串\([l,r]\),合法的必要条件是\(l\)的后缀在后缀数组的排名小于\(r\)的前缀的排名。之所以是必要条件,是因为会记入一些\([l,r]\)是回文串且\(l\)的排名小的情况。具体而言,这......
  • P1686 挑战 题解
    原题链接题目大意\(图上两个x或y值相同的点,如果其没有一条线段直接相连,则这两个点之间的距离为一条捷径\)\(给定一条路径,求此路径上最短的捷径长度(注意,是捷径最短)以及捷径的起止点和方向\)数据范围\(1\len\le250000\)\(先考虑x值相同的情况,假设有3个点A,B,C可以互相构成......