【BZOJ4016】[FJOI2014]最短路径树问题(Dijkstra+长链剖分+树状数组)

版权声明:转载请声明 https://blog.csdn.net/ezoiHQM/article/details/82896388

题目链接
首先最短路径树我们可以直接用Dijkstra来求(不用字典序也能过2333)。
求完最短路径树之后呢,就可以用长链剖分+树状数组来求最长的包含K个点的简单路径长度为多长和长度为该最长长度的不同路径有多少条(也可以用点分治,但是我点分治学得太差了就写了长链。打模拟赛的时候感觉所有其它人写的都是点分,就我一个人写了长链2333)。具体就看代码好了。
如果有误在评论区吼一声哦!
代码:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,k,tot,cnt,siz,ans1,ans2,head[30010],to[120010],nxt[120010],val[120010],ct[30010],pre[30010],vl[30010],dis[30010],dep[30010],nd[30010],son[30010],maxn[30010],dfn[30010],rnk[30010],tr[30010];
pair<int,int>heap[30010];
char buffer[1000010],*hd,*tl;
inline char Getchar(){
	if(hd==tl){
		int len=fread(buffer,1,1000000,stdin);
		hd=buffer,tl=hd+len;
		if(hd==tl)
			return EOF;
	}
	return *hd++;
}
inline int rd(){
	register int x=0;
	char c;
	do c=Getchar();
	while(!isdigit(c));
	do{
		x=(x<<1)+(x<<3)+(c^48);
		c=Getchar();
	}while(isdigit(c));
	return x;
}
inline void add_edge(int u,int v,int w){
	nxt[++tot]=head[u];
	to[tot]=v;
	val[tot]=w;
	head[u]=tot;
	return;
}
inline void readData(){
	n=rd(),m=rd(),k=rd();
	for(register int i=1;i<=m;i++){
		int u=rd(),v=rd(),w=rd();
		add_edge(u,v,w);
		add_edge(v,u,w);
	}
	return;
}
inline void Push(pair<int,int>x){
	heap[++siz]=x;
	push_heap(heap+1,heap+siz+1,greater<pair<int,int> >());
	return;
}
inline pair<int,int>t_and_p(){
	pop_heap(heap+1,heap+siz+1,greater<pair<int,int> >());
	return heap[siz--];
}
inline void Dijkstra(int S){
	Push(make_pair(0,S));
	memset(dis,127,sizeof(dis));
	dis[S]=0;
	while(siz){
		pair<int,int>tmp=t_and_p();
		int u=tmp.second;
		if(dis[u]!=tmp.first)
			continue;
		for(int i=head[u];i;i=nxt[i]){
			int v=to[i],w=val[i];
			if(dis[u]+w<dis[v]){
				pre[v]=u;
				vl[v]=w;
				Push(make_pair(dis[v]=dis[u]+w,v));
			}
		}
	}
	return;
}
inline void Build(){
	memset(head,-1,sizeof(head));
	tot=0;
	for(register int i=1;i<=n;i++){
		for(register int x=i;x;){
			if(!pre[x])
				break;
			add_edge(pre[x],x,vl[x]);
			add_edge(x,pre[x],vl[x]);
			int tmp=x;
			x=pre[x];
			pre[tmp]=0;
		}
	}
	return;
}
inline int lowbit(int x){
	return x&(-x);
}
inline int query(int x){
	register int ret=0;
	while(x){
		ret+=tr[x];
		x-=lowbit(x);
	}
	return ret;
}
inline void update(int x,int v){
	while(x<=n){
		tr[x]+=v;
		x+=lowbit(x);
	}
	return;
}
inline void update(int l,int r,int v){
	update(l,v);
	update(r+1,-v);
	return;
}
void dfs1(int u,int father){
	maxn[u]=1;
	for(register int i=head[u];~i;i=nxt[i]){
		int v=to[i],w=val[i];
		if(v==father)
			continue;
		dep[v]=dep[u]+1;
		dfs1(v,u);
		if(maxn[v]+1>maxn[u])
			maxn[u]=maxn[v]+1,son[u]=v,vl[u]=w;
	}
	return;
}
void dfs2(int u,int father){
	rnk[dfn[u]=++cnt]=u;
	if(!son[u]){
		nd[u]=cnt;
		return;
	}
	dfs2(son[u],u);
	nd[u]=nd[son[u]];
	for(register int i=head[u];~i;i=nxt[i]){
		int v=to[i];
		if(v!=father&&v!=son[u])
			dfs2(v,u);
	}
	return;
}
void DP(int u,int father){
	ct[dfn[u]]=1;
	if(!son[u])
		return;
	DP(son[u],u);
	update(dfn[u]+1,nd[u],vl[u]);
	if(maxn[u]>=k){
		int tmp=query(dfn[u]+k-1);
		if(tmp>ans1){
			ans1=tmp;
			ans2=0;
		}
		if(tmp==ans1)
			ans2+=ct[dfn[u]+k-1];
	}
	for(register int i=head[u];~i;i=nxt[i]){
		int v=to[i],w=val[i];
		if(v==son[u]||v==father)
			continue;
		DP(v,u);
		for(register int i=1;i<=min(k-1,maxn[v]);i++){
			if(maxn[u]<k-i)
				continue;
			int tmp=query(dfn[v]+i-1)+query(dfn[u]+k-i-1)+w;
			if(tmp>ans1){
				ans1=tmp;
				ans2=0;
			}
			if(tmp==ans1)
				ans2+=ct[dfn[u]+k-i-1]*ct[dfn[v]+i-1];
		}
		for(register int i=1;i<=maxn[v];i++){
			int tmp1=query(dfn[u]+i),tmp2=query(dfn[v]+i-1)+w;
			if(tmp1<tmp2){
				update(dfn[u]+i,dfn[u]+i,tmp2-tmp1);
				ct[dfn[u]+i]=ct[dfn[v]+i-1];
			}
			else if(tmp1==tmp2)
				ct[dfn[u]+i]+=ct[dfn[v]+i-1];
		}
	}
	return;
}
inline void Getans(){
	dfs1(1,0);
	dfs2(1,0);
	DP(1,0);
	printf("%d %d\n",ans1,ans2);
	return;
}
int main(){
	readData();
	Dijkstra(1);
	Build();
	Getans();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ezoiHQM/article/details/82896388