zoukankan      html  css  js  c++  java
  • Luogu 4149 Race

    Luogu 4149 Race

    • 用点分治解决.
    • 点分治在计算路径贡献时,为了不统计在一颗子树中的路径,解决方法一种是容斥,但在这种求最值问题中不便用容斥来撤销.
    • 另一种则是,处理一颗子树时,只考虑前面的子树中产生的贡献,而将当前的子树的节点暂时存储在一个栈中,当前子树处理完毕后,再让栈中的点产生贡献,就可以解决求最值等容斥难以处理的问题.
    • 就本题而言,记 (tmp[i]) 表示路径长度为 (i) 的路径中最少的边数.那么每条路径就可以更新答案 (ans=min{ans,edges+tmp[k-len]}).将当前子树的点存入 (s2) 中,处理完后再用 (s2) 内的路径更新 (tmp).
    • (tmp) 每次要初始化为 (inf) ,为了避免每次遍历所有点,可以记录哪些位置被修改过(记录在 (s1) 中),只用给它们赋值就可以了.
    #include<bits/stdc++.h>
    #define mp make_pair
    #define inf 1e9
    using namespace std;
    typedef pair<int,int> pii;
    typedef long long ll;
    inline int read()
    {
    	int out=0,fh=1;
    	char jp=getchar();
    	while ((jp>'9'||jp<'0')&&jp!='-')
    		jp=getchar();
    	if (jp=='-')
    		fh=-1,jp=getchar();
    	while (jp>='0'&&jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*fh;
    }
    const int MAXN=2e5+10;
    int ans=inf;
    int cnt=0,head[MAXN],to[MAXN<<1],nx[MAXN<<1],val[MAXN<<1];
    inline void addedge(int u,int v,int w)
    {
    	++cnt;
    	to[cnt]=v;
    	nx[cnt]=head[u];
    	val[cnt]=w;
    	head[u]=cnt;
    }
    int n,k;
    int vis[MAXN];
    int totsiz,sonsiz[MAXN],siz[MAXN],mi,rt;
    void findrt(int u,int fa)
    {
    	siz[u]=1;
    	sonsiz[u]=0;
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(v==fa || vis[v])
    				continue;
    			findrt(v,u);
    			siz[u]+=siz[v];
    			sonsiz[u]=max(sonsiz[u],siz[v]);
    		}
    	sonsiz[u]=max(sonsiz[u],totsiz-siz[u]);
    	if(sonsiz[u]<mi)
    		mi=sonsiz[u],rt=u;
    }
    int len[MAXN],edges[MAXN];
    int tmp[1000000+10];
    int s1[MAXN],s2[MAXN];
    int tp1,tp2;
    void getdis(int u,int fa)
    {
    	if(k>=len[u])
    		ans=min(ans,edges[u]+tmp[k-len[u]]);
    	s2[++tp2]=u;
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(v==fa || vis[v])
    				continue;
    			len[v]=len[u]+val[i];
    //			assert(len[v]<=1000000);
    			edges[v]=edges[u]+1;
    			getdis(v,u);
    		}
    }
    void solve(int u)
    {
    	len[u]=edges[u]=0;
    	for(int i=1;i<=tp1;++i)
    		tmp[s1[i]]=inf;
    	s1[tp1=1]=u;
    	tmp[0]=0;
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(vis[v])
    				continue;
    			tp2=0;
    			len[v]=val[i],edges[v]=1;
    			getdis(v,u);
    			for(int j=1;j<=tp2;++j)
    				{
    					v=s2[j];
    					tmp[len[v]]=min(tmp[len[v]],edges[v]);
    					s1[++tp1]=len[v];
    				}
    		}
    }
    void divide(int u)
    {
    	solve(u);
    	vis[u]=1;
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(vis[v])
    				continue;
    			mi=inf,totsiz=siz[v];
    			findrt(v,0);
    			divide(rt);
    		}
    }
    int main()
    {
    //	freopen("testdata.in","r",stdin);
    	n=read(),k=read();
    	for(int i=1;i<n;++i)
    		{
    			int u=read()+1,v=read()+1,w=read();
    			addedge(u,v,w);
    			addedge(v,u,w);
    		}	
    	for(int i=0;i<=1000000;++i)
    		tmp[i]=inf;
    	mi=inf,totsiz=n;
    	findrt(1,0);
    	divide(rt);
    	cout<<(ans==inf?-1:ans)<<endl;
    	return 0;
    }
    
  • 相关阅读:
    Android 生命周期
    adb 的相关操作及遇到的问题
    各种内部类
    Android 的系统架构
    Hibernate的各种关联关系
    Eclipse常用的快捷键
    Android 开发前的基本的配置及第一个Android 程序
    spring MVC Validation(表单验证)
    创建 spring MVC项目的基本步骤
    Android_demo之生成二维码
  • 原文地址:https://www.cnblogs.com/jklover/p/10577640.html
Copyright © 2011-2022 走看看