• 【CF757F】 Team Rocket Rises Again 【支配树】


    Description

    • 传送门
    • 题意:给定一个(n)个点,(m)条边的带权无向图,和起点(s)。选择一个点(u)(u eq s)),使在图中删掉点(u)后,有尽可能多的点到(s)的最短距离改变。
    • (1le n le 2*10^5,1le m le 3*10^5),给出的图无重边无自环,不保证连通。

    Solution

    破坏最短路可以建出最短路树后转化为破坏所有路径,于是就变成了一个裸的支配树问题,我们只需要求出除(s)之外所有点支配树上的子树大小的最大值即可。
    最短路树是一个(DAG),于是套支配树的模板即可。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=6e5+10;
    typedef long long ll;
    typedef pair<ll,int> pli;
    #define mp make_pair
    inline int read(){
    	int x=0,f=1;
    	char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,m,s;
    struct node{
    	int v,w,nxt;
    };
    struct graph{
    	int first[N],cnt;
    	node e[N];
    	inline void add(int u,int v,int w=0){
    		e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=first[u];first[u]=cnt;
    	}
    }g,tr;//原图与最短路树 
    int vis[N];
    ll dis[N];
    vector<int> ru[N];
    inline void dijkstra(){
    	priority_queue<pli> q;
    	memset(dis,0x3f,sizeof(dis));
    	dis[s]=0;
    	q.push(mp(0,s));
    	while(!q.empty()){
    		int u=q.top().second;q.pop();if(vis[u]) continue;
    		for(int i=g.first[u];i;i=g.e[i].nxt){
    			int v=g.e[i].v,w=g.e[i].w;
    			if(dis[u]+w<dis[v]){
    				dis[v]=dis[u]+w;
    				q.push(make_pair(-dis[v],v));
    			}
    		}
    	}
    	for(int i=1;i<=n;++i){
    		for(int j=g.first[i];j;j=g.e[j].nxt){
    			int v=g.e[j].v;
    			if(dis[v]!=dis[i]+g.e[j].w) continue;
    			ru[v].push_back(i),tr.add(i,v); 
    		}
    	}
    }
    namespace dt{
    	int ans,dep[N],pa[N][20],tot,head[N],siz[N],top[N],de[N];
    	node d[N<<1];
    	inline void Add(int u,int v){
    		dep[v]=dep[u]+1;
    		pa[v][0]=u;
    		for(int i=1;i<=19;++i) pa[v][i]=pa[pa[v][i-1]][i-1];
    		d[++tot].v=v;d[tot].nxt=head[u];head[u]=tot;
    	}
    	inline int LCA(int u,int v){
    		if(dep[u]<dep[v]) swap(u,v);
    		int t=dep[u]-dep[v];
    		for(int i=19;i>=0;--i) if(t&(1<<i)) u=pa[u][i];
    		if(u==v) return u;
    		for(int i=19;i>=0;--i) if(pa[u][i]!=pa[v][i]) u=pa[u][i],v=pa[v][i];
    		return pa[u][0];
    	}
    	inline void dfs(int u){
    		siz[u]=1;
    		for(int i=head[u];i;i=d[i].nxt){
    			int v=d[i].v;
    			if(v!=pa[u][0]) dfs(v),siz[u]+=siz[v];
    		}
    		if(u!=s) ans=max(ans,siz[u]);
    	}
    	inline void build(){
    		queue<int> q;
    		q.push(s);
    		for(int i=1;i<=n;++i) de[i]=ru[i].size();
    		while(!q.empty()){
    			int u=q.front();q.pop();
    			top[++tot]=u;
    			for(int i=tr.first[u];i;i=tr.e[i].nxt){
    				int v=tr.e[i].v;
    				if(!(--de[v])) q.push(v);
    			}
    		}
    		for(int i=2;i<=n;++i){
    			int u=top[i],lca=0;
    			for(int j=0;j<ru[u].size();++j){
    				int v=ru[u][j];
    				if(!lca) lca=v;
    				else lca=LCA(lca,v);
    			}
    			Add(lca,u);
    		}
    		dfs(s);
    		printf("%d
    ",ans);
    	}
    }
    int main(){
    	n=read();m=read();s=read();
    	for(int i=1,u,v,w;i<=m;++i){
    		u=read();v=read();w=read();
    		g.add(u,v,w);g.add(v,u,w);
    	}
    	dijkstra();
    	dt::build();
    	return 0;
    }
    
  • 相关阅读:
    window.print()分页打印
    获取输入框中光标位置
    JavaScript数据结构与算法描述-队列
    .NET中获取IP地址
    记录一次排查C#使用UI Automation获取程序元素的bug
    虚拟机为win server 2012 添加新磁盘
    为halo博客添加ssl证书(配合nginx反向代理)
    初学nginx反向代理
    公告时间轴
    hackthebox-Archetype
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14289291.html
Copyright © 2020-2023  润新知