[WC2010]重建计划

重建计划

题解

看到这道题首先应该是很容易想到0/1分数规划的。毕竟那里明摆着一个 ∑ i = 1 k − 1 v a l i ∣ S ∣ \frac{\sum_{i=1}^{k-1}val_{i}}{|S|} Si=1k1vali
我们只需要将下面的分母当做 1 1 1即可,所以当二分到 m i d mid mid时,若 m i d mid mid可呗构造出来,有 ∑ i = 1 k − 1 v a l i ∣ S ∣ ≥ m i d ⟺ ∑ i = 1 k − 1 ( v a l i − m i d ) ≥ 0 \frac{\sum_{i=1}^{k-1}val_{i}}{|S|}\geq mid\Longleftrightarrow \sum_{i=1}^{k-1}(val_{i}-mid)\geq 0 Si=1k1valimidi=1k1(valimid)0
所以我们只需判断当前的 m i d mid mid跑出来的有无权值大于0的合法路径即可。

关键是怎么找这个路径。
由于它求的是任意点对 ( u , v ) (u,v) (u,v)的路径长度最大值,我们很快就想到了点分治。
我们可以通过点分治来找到这些路径的最大长度。
在一个点的子树里统计的时候,我们就先对它的每个儿子的子树跑bfs,找到它的儿子在 [ 0 , U ) [0,U) [0,U)的边数内,每种边数的最深距离,再像树dp一样进行合并,用 f i f_{i} fi表示深度为 i i i时的最长路径。
合并之前将两个未合并的部分与新求出来的部分一起统计答案,每个 f f f对应的区间的 b f s bfs bfs序一定是连续的,我们可以用单调队列来求出最大值,这个过程时间复杂度是 O ( 子树大小 ) O\left(子树大小\right) O(子树大小)的。

由于点分治最多只会有 l o g n log_{n} logn层,所以每次判读时间复杂度是 O ( n l o g   n ) O\left(nlog\,n\right) O(nlogn)的。
由于点分治的过程是一直沿着重心下去的,我们可以先预处理重心的顺序,这样分治每次判断时就不用单独处理了。

总时间复杂度 O ( n l o g 2   n ) O\left(nlog^2\,n\right) O(nlog2n)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n,L,U,head[MAXN],tot,mxson[MAXN],siz[MAXN],S,mx;
int root[MAXN],idx,sta[MAXN],stak,las,len[MAXN],q[MAXN];
double dis[MAXN],f[MAXN];bool vis[MAXN],vp[MAXN],flag;
struct ming{int u,v,w;}a[MAXN];
struct edge{int to,nxt;double paid;}e[MAXN<<1];
void addEdge(int u,int v,double w){e[++tot]=(edge){v,head[u],w};head[u]=tot;}
void bfs(int st){
	vp[sta[++stak]=st]=1;
	for(int i=las+1;i<=stak;i++)
		for(int j=head[sta[i]];j;j=e[j].nxt){
			int v=e[j].to;if(vis[v]||vp[v])continue;
			dis[v]=dis[sta[i]]+e[j].paid;
			len[v]=len[sta[i]]+1;vp[sta[++stak]=v]=1;
		}
	for(int i=las+1;i<=stak;i++)vp[sta[i]]=0;
}
void check(){
	int head=1,tail=0,id=las+1;
	for(int i=min(U,len[sta[stak]]);i>=0;i--){
		int tl=max(L-i,0),tr=U-i;
		while(head<=tail&&len[q[head]]<tl)head++;
		while(id<=stak&&len[sta[id]]<tl)++id;
		while(id<=stak&&len[sta[id]]<=tr){
			while(head<=tail&&dis[q[tail]]<=dis[sta[id]])tail--;
			q[++tail]=sta[id++];
		}
		if(head<=tail&&f[i]+dis[q[head]]>=0)return (void)(flag=1);
	}
}
void devide(int x){
	vis[x]=1;f[0]=dis[x]=len[x]=0;sta[++stak]=x;
	for(int i=head[x];i;i=e[i].nxt){
		int v=e[i].to;if(vis[v])continue;
		las=stak;dis[v]=e[i].paid;len[v]=1;bfs(v);check();
		for(int j=las+1;j<=stak;j++)
			f[len[sta[j]]]=max(f[len[sta[j]]],dis[sta[j]]);
	}  
	while(stak)f[len[sta[stak--]]]=-INF;
	for(int i=head[x];i;i=e[i].nxt)if(!vis[e[i].to])devide(root[++idx]);
}
bool sakura(double mid){
	idx=tot=0;for(int i=1;i<=n;i++)head[i]=vis[i]=0;
	for(int i=1;i<n;i++)
		addEdge(a[i].u,a[i].v,1.0*a[i].w-mid),
		addEdge(a[i].v,a[i].u,1.0*a[i].w-mid);
	flag=0;devide(root[++idx]);return flag;
}
void getroot(int u,int fa){
	siz[u]=1;mxson[u]=0;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;if(v==fa||vis[v])continue;getroot(v,u);
		siz[u]+=siz[v];mxson[u]=max(siz[v],mxson[u]);
	}
	mxson[u]=max(mxson[u],S-siz[u]);
	if(mxson[u]<mx){mx=mxson[u];root[idx]=u;}
}
void dfs(int u){
	vis[u]=1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;if(vis[v])continue;
		S=siz[v];++idx;mx=INF;getroot(v,0);dfs(root[idx]);
	}
}
void init(){
	tot=0;for(int i=1;i<=n;i++)head[i]=0;
	for(int i=1;i<n;i++)addEdge(a[i].u,a[i].v,0),addEdge(a[i].v,a[i].u,0);
	mx=INF;S=n;++idx;getroot(1,0);dfs(root[idx]);
}
signed main(){
	read(n);read(L);read(U);
	for(int i=1;i<n;i++)read(a[i].u),read(a[i].v),read(a[i].w);
	for(int i=0;i<n;i++)f[i]=-INF;
	init();double l=0,r=1e6,times=40,Ans=r;
	while(times--){
		double mid=(l+r)/2.0;
		if(sakura(mid))l=mid,Ans=mid;
		else r=mid;
	}
	printf("%.3f\n",Ans);
	return 0;
}

谢谢!!!

### MATLAB 中时域信号的采样与重建方法 #### 1. 信号采样的基本原理 在 MATLAB 中,对于时域信号的处理通常涉及两个主要过程:采样和重建。采样是指按照一定的时间间隔获取离散的数据点;而重建则是通过这些离散数据点恢复原始连续信号的过程。 为了确保能够无失真地还原原信号,在奈奎斯特-香农采样定理指导下,采样频率应当至少两倍于待测信号中的最高频成分[^1]。 #### 2. 使用 `interp` 函数进行简单插值重建 当已知一组经过均匀或不均匀分布采样的样本值时,可以通过线性或其他形式的内插法近似得到任意位置上的估计值。MATLAB 提供了一个名为 `interp` 的内置函数用于此目的: ```matlab % 假设 x_sampled 是已经过低通滤波后的离散化输入序列, % fs 和 fs_new 分别代表旧的新采样率。 x_reconstructed = interp(x_sampled, fs / fs_new); ``` 这段代码实现了简单的重采样操作,并将结果存储到变量 `x_reconstructed` 中[^2]。 #### 3. 利用 sinc 插值实现更精确的信号重构 相比于上述较为基础的方法,采用 Whittaker–Shannon 内插公式(即理想低通信号重构)可以获得更加接近真实的输出效果。具体来说就是利用 sinc 函数作为权重因子加权求和各个采样点处的信息量来逼近目标区间内的实际数值变化趋势。 下面给出了一段具体的实现代码片段: ```matlab Ts = 0.24; % 设定合适的采样周期 T_s t = -3 : Ts : 3; f = rectpuls(t, 2); % 构造矩形脉冲测试信号 ws = 2 * pi / Ts; wc = ws / 2; Dt = 0.01; t1 = -3 : Dt : 3; % 更细密的时间轴定义以便观察细节特征 fa = Ts * wc / pi .* (f' * sinc((wc / pi) * ((ones(length(t), 1) * t1') - ... repmat(t', 1, length(t1))))); figure(); plot(t1, fa); xlabel('Time'); ylabel('Amplitude'); title('Reconstructed Signal of f(t)'); ``` 该部分展示了如何基于给定条件下的采样数据集构建出相对完整的模拟曲线图象[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值