zoukankan      html  css  js  c++  java
  • P2993 [FJOI2014]最短路径树问题

    主要考察知识:点分治+最短路径生成树。

    PART #1:最短路径生成树

    相当于在跑(dijkstra)的时候记个路径所构成的树。

    证明:1.除1外每个点均连一条边,故为(n-1)条边。

    2.每个点均向最短路严格小于自己的点连边,故无环。

    则一定为树,证毕。

    注意:由于此题求最长路径,故选取最长的边,如下:

    if(dis[t]>dis[x]+w[i]){
    	dis[t]=dis[x]+w[i];
    	pre[t]=x;val[t]=w[i];
    	q.push(make_pair(-dis[t],t));
    }else if(dis[t]==dis[x]+w[i]&&w[i]>val[t]){
    	pre[t]=x;val[t]=w[i];
    }
    

    PART #2:点分治

    请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?

    长度为该最长长度的不同路径有多少条?

    在树上询问定长路径相关问题是经典的点分治问法。

    还不会点分治的同学推荐看这篇博客

    点分时处理对应长度出现的最大值及出现次数。

    注意:1.及时清零数组以防超时。

    2.处理完每个子数再递归,以防数组在下层中被改变。

    时间复杂度(O(nlogn))

    完整代码如下,仅供参考:

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=2e5+10;
    const int mod=1e9+7;
    int n,m,k;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int beg[maxn],nex[maxn],to[maxn],w[maxn],e;
    inline void add(int x,int y,int z){
    	e++;nex[e]=beg[x];
    	beg[x]=e;to[e]=y;w[e]=z;
    }
    int dis[maxn],vis[maxn],pre[maxn],val[maxn];
    priority_queue<pair<int,int> >q;
    int ans,num,rt,mx,size,siz[maxn],son[maxn];
    inline void getrt(int x,int fa){
    	siz[x]=1;son[x]=0;
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];
    		if(t==fa||vis[t])continue;
    		getrt(t,x);
    		siz[x]+=siz[t];
    		if(son[x]<siz[t])son[x]=siz[t];
    	}
    	if(son[x]<size-siz[x])son[x]=size-siz[x];
    	if(mx>son[x])mx=son[x],rt=x;
    }
    int bot[maxn],cou[maxn],zyf[maxn],whm[maxn],tmp;
    inline void calc(int x,int fa,int dist,int dep){
    	if(zyf[dep]<dist){
    		zyf[dep]=dist;
    		whm[dep]=1;
    	}else if(zyf[dep]==dist)
    		whm[dep]++;
    	if(dep>tmp)tmp=dep;
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];
    		if(t==fa||vis[t])continue;
    		calc(t,x,dist+w[i],dep+1);
    	}
    }
    inline void solve(int x){
    	cou[0]=vis[x]=1;
    	int dep=0;
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];tmp=0;
    		if(vis[t])continue;
    		calc(t,x,w[i],1);
    		if(tmp>dep)dep=tmp;
    		for(int j=1;j<=tmp;j++)
    			if(cou[k-1-j])
    				if(ans<zyf[j]+bot[k-1-j]){
    					ans=zyf[j]+bot[k-1-j];
    					num=whm[j]*cou[k-1-j];
    				}else if(ans==zyf[j]+bot[k-1-j])
    					num+=whm[j]*cou[k-1-j];
    		for(int j=1;j<=tmp;j++)
    			if(zyf[j]>bot[j]){
    				bot[j]=zyf[j];
    				cou[j]=whm[j];
    			}else if(zyf[j]==bot[j])
    				cou[j]+=whm[j];
    		for(int j=1;j<=tmp;j++)
    			zyf[j]=whm[j]=0;
    	}
    	for(int i=0;i<=dep;i++)
    		bot[i]=cou[i]=0;
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];
    		if(vis[t])continue;
    		rt=0,mx=inf,size=siz[t];
    		getrt(t,x);
    		solve(rt);
    	}
    }
    int main(){
    	n=read(),m=read(),k=read();
    	int x,y,z;
    	for(int i=1;i<=m;i++){
    		x=read(),y=read(),z=read();
    		add(x,y,z),add(y,x,z);
    	}
    	memset(dis,0x3f,sizeof(dis));
    	dis[1]=0;q.push(make_pair(0,1));
    	while(!q.empty()){
    		x=q.top().second;
    		q.pop();
    		if(vis[x])continue;
    		vis[x]=1;
    		for(int i=beg[x];i;i=nex[i]){
    			int t=to[i];
    			if(dis[t]>dis[x]+w[i]){
    				dis[t]=dis[x]+w[i];
    				pre[t]=x;val[t]=w[i];
    				q.push(make_pair(-dis[t],t));
    			}else if(dis[t]==dis[x]+w[i]&&w[i]>val[t]){
    				pre[t]=x;val[t]=w[i];
    			}
    		}
    	}
    	e=0;memset(beg,0,sizeof(beg));
    	for(int i=2;i<=n;i++)
    		add(i,pre[i],val[i]),add(pre[i],i,val[i]);
    	mx=inf,size=n,rt=0;
    	memset(vis,0,sizeof(vis));
    	getrt(1,0);
    	solve(rt);
    	printf("%d %d
    ",ans,num);
    	return 0;
    }
    

    深深地感到自己的弱小。

  • 相关阅读:
    Linux 函数库
    Linux yum源码包安装和卸载
    Linux软件包管理 RMP包
    Linux软件包管理 RMP包管理
    Linux基本命令 vim命令(二)
    Linux基本命令 vim命令(一)
    Linux基本命令 关机命令
    【后缀表达式求解】No.3.栈-evaluate-reverse-polish-notation题解(Java版)
    对象输入输出流ObjectInputStream、ObjectOutputStream(对象的序列化与反序列化)
    手写二叉树-先序构造(泛型)-层序遍历(Java版)
  • 原文地址:https://www.cnblogs.com/syzf2222/p/13766009.html
Copyright © 2011-2022 走看看