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

    建树+点分治 难度在于建树

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #define sc second
    #define pr pair<int,int>
    #define mp make_pair
    using namespace std;
    int root,Cnt,F_top,cnt,n,m,K,N,instack[1000005],last[1000005],vis[1000005],dis[1000005],F_[1000005],F[1000005],G[1000005],F_stack[1000005],G_stack[1000005],F_sum[1000005],G_sum[1000005],sz[1000005];
    long long ans,ans_sum;
    priority_queue<pr,vector<pr>,greater<pr> > q;
    struct node{
    	int to,next,val;
    }e[1000005];
    void add(int a,int b,int c){
    	e[++cnt].to=b;
    	e[cnt].next=last[a];
    	e[cnt].val=c;
    	last[a]=cnt;
    }
    void Dijkstra(int S){
    	for (int i=1; i<=n; i++) vis[i]=0,dis[i]=1e9;
    	dis[S]=0;
    	q.push(mp(0,S));
    	while (!q.empty()){
    		int x=q.top().sc;
    		q.pop();
    		if (vis[x]) continue;
    		vis[x]=1;
    		for (int i=last[x]; i; i=e[i].next){
    			int V=e[i].to;
    			if (dis[V]>dis[x]+e[i].val){
    				dis[V]=dis[x]+e[i].val;
    				q.push(mp(dis[V],V));
    			}
    		}
    	}
    }
    struct node1{
    	int x,val;
    };
    vector<node1> vec[1000005];
    bool cmp(node1 a,node1 b){
    	return a.x<b.x;
    }
    struct node2{
    	int x,y,val;
    }E[1000005];
    void dfs(int x){
    	vis[x]=1;
    	for (int i=last[x]; i; i=e[i].next){
    		int V=e[i].to;
    		vec[x].push_back((node1){V,e[i].val});
    	}
    	sort(vec[x].begin(),vec[x].end(),cmp);
    	for (int i=0; i<(int)vec[x].size(); i++){
    		int V=vec[x][i].x;
    		if (dis[V]==dis[x]+vec[x][i].val && !vis[V]) {
    			E[++Cnt]=(node2){x,V,vec[x][i].val};
    			dfs(V);
    		}
    	}
    }
    void find_root(int x,int fa){
    	sz[x]=1,F_[x]=0;
    	for (int i=last[x]; i; i=e[i].next){
    		int V=e[i].to;
    		if (vis[V] || V==fa) continue;
    		find_root(V,x);
    		sz[x]+=sz[V];
    		F_[x]=max(F_[x],sz[V]);
    	}
    	F_[x]=max(F_[x],N-sz[x]);
    	if (F_[x]<F_[root]) root=x;
    }
    void get_dis(int x,int fa,int val,int dep){
    	if (dep==K){
    		int ANS=val,ANS_sum=1;
    		if (ANS==ans) ans_sum+=ANS_sum;
    		else if (ANS>ans) ans=ANS,ans_sum=ANS_sum;
    	}
    	if (!instack[dep]) F_stack[++F_top]=dep,instack[dep]=1;
    	if (F[dep]==val) F_sum[dep]++;
    	else if (F[dep]<val) F[dep]=val,F_sum[dep]=1;
    	sz[x]=1;
    	for (int i=last[x]; i; i=e[i].next){
    		int V=e[i].to;
    		if (vis[V] || V==fa) continue;
    		get_dis(V,x,val+e[i].val,dep+1);
    		sz[x]+=sz[V];
    	}
    }
    void solve(int x){
    	int G_top=0;
    	for (int i=last[x]; i; i=e[i].next){
    		int V=e[i].to;
    		if (vis[V]) continue;
    		F_top=0;
    		get_dis(V,x,e[i].val,2);
    		for (int j=1; j<=F_top; j++) 
    			if (K+1-F_stack[j]>=1){
    				int ANS=F[F_stack[j]]+G[K+1-F_stack[j]];
    				long long ANS_sum=1ll*F_sum[F_stack[j]]*G_sum[K+1-F_stack[j]];
    				if (ANS==ans) ans_sum+=ANS_sum;
    				else if (ANS>ans) ans=ANS,ans_sum=ANS_sum;
    			}
    		for (int j=1; j<=F_top; j++)
    			if (F[F_stack[j]]==G[F_stack[j]]) G_sum[F_stack[j]]+=F_sum[F_stack[j]];
    			else if (F[F_stack[j]]>G[F_stack[j]]) G[F_stack[j]]=F[F_stack[j]],G_sum[F_stack[j]]=F_sum[F_stack[j]];
    		for (int j=1; j<=F_top; j++) F[F_stack[j]]=0,instack[F_stack[j]]=0,G_stack[++G_top]=F_stack[j];
    	}
    	for (int i=1; i<=G_top; i++) G[G_stack[i]]=0;
    }
    void divide(int x){
    	vis[x]=1;
    	solve(x);
    	for (int i=last[x]; i; i=e[i].next){
    		int V=e[i].to;
    		if (vis[V]) continue;
    		N=sz[V],root=0;
    		find_root(V,x);
    		divide(root);
    	}
    }
    int main(){
    	scanf("%d%d%d",&n,&m,&K);
    	for (int i=1; i<=m; i++){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z);
    		add(y,x,z);
    	}
    	Dijkstra(1);
    	memset(vis,0,sizeof(vis));
    	dfs(1);
    	F_[0]=1e9;
    	cnt=0;
    	memset(last,0,sizeof(last));
    	for (int i=1; i<=Cnt; i++) add(E[i].x,E[i].y,E[i].val),add(E[i].y,E[i].x,E[i].val);
    	memset(vis,0,sizeof(vis));
    	N=n,root=0;
    	find_root(1,0);
    	divide(root);
    	printf("%lld %lld
    ",ans,ans_sum);
    	return 0;
    }
    /*
    4 6 2
    1 2 5
    1 4 2
    2 4 6
    2 3 6
    3 4 5
    1 3 1
    */
    

      

  • 相关阅读:
    ZOJ 3818 Pretty Poem
    HDU 4597 Play Game
    HDU 4497 GCD and LCM
    CSU 1335 高桥和低桥
    UVA 10791 Minimum Sum LCM
    CSU 1119 Collecting Coins
    CSU 1120 病毒
    UVA 12169 Disgruntled Judge
    HDU 1301 Jungle Roads
    POJ 1258 Agri-Net
  • 原文地址:https://www.cnblogs.com/silenty/p/9786102.html
Copyright © 2011-2022 走看看