• BZOJ4912 [Sdoi2017]天才黑客 【虚树 + 最短路】


    题目链接

    BZOJ4912

    题解

    转移的代价是存在于边和边之间的
    所以把边看做点,跑最短路
    但是这样做需要把同一个点的所有入边和所有出边之间连边
    (O(m^2))的连边无法接受
    需要优化建图

    膜一下Claris的方法
    对每个点,取出其入边出边,按在字典树上的(dfs)序排序
    (dfs)序排序,实际上就是将字符串排序了
    按照后缀数组的理论,两点之间的(lcp)就是两点之间相邻(lcp),也就是(height)数组的最小值
    对于一个位置的(height),两边的点之间联通所需最小代价不超过(height)
    所以可以用(lca)求出(height)数组,建立前缀后缀虚点
    以前缀为例,横向边为(0),纵向边为(height)的大小

    这样如果想从左边的点到达右边的点,就只需经过中间最小的(height)
    类似可以建立后缀点处理从右到左的情况

    复杂度(O(mlogm))

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define cls(s,v) memset(s,v,sizeof(s))
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cp pair<int,int>
    using namespace std;
    const int maxn = 500005,maxm = 2000005,INF = 2000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
    	return flag ? out : -out;
    }
    struct EDGE{int to,nxt,w;}ed[maxm];
    struct Trie{
    	int h[maxn],ne,dfn[maxn],fa[maxn][16],dep[maxn],cnt,n;
    	EDGE ed[maxm];
    	void init(){REP(i,n) h[i] = 0; ne = 1; cnt = 0;}
    	void build(int u,int v){ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;}
    	void dfs(int u){
    		dfn[u] = ++cnt;
    		REP(i,15) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    		Redge(u) {
    			fa[to = ed[k].to][0] = u;
    			dep[to] = dep[u] + 1; dfs(to);
    		}
    	}
    	int lca(int u,int v){
    		if (dep[u] < dep[v]) swap(u,v);
    		for (int D = dep[u] - dep[v],i = 0; (1 << i) <= D; i++)
    			if (D & (1 << i)) u = fa[u][i];
    		if (u == v) return u;
    		for (int i = 15; ~i; i--)
    			if (fa[u][i] != fa[v][i]){
    				u = fa[u][i];
    				v = fa[v][i];
    			}
    		return fa[u][0];
    	}
    }T;
    int h[maxn],ne = 1;
    int n,m,N,w[maxn],pos[maxn];
    int c[maxn],ci,height[maxn];
    int pu[maxn],pd[maxn],su[maxn],sd[maxn];
    int d[maxn],vis[maxn];
    vector<int> in[maxn],out[maxn];
    priority_queue<cp,vector<cp>,greater<cp> > q;
    inline void build(int u,int v,int w){ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;}
    inline bool cmp(const int& a,const int& b){
    	return T.dfn[pos[abs(a)]] < T.dfn[pos[abs(b)]];
    }
    void init(){
    	T.init(); ne = 1; N = 0; cls(h,0); cls(w,0);
    	REP(i,n) in[i].clear(),out[i].clear();
    }
    void Build(){
    	for (int p = 1; p <= n; p++){
    		if (!in[p].size() && !out[p].size()) continue;
    		ci = 0;
    		for (unsigned int i = 0; i < in[p].size(); i++)
    			c[++ci] = in[p][i];
    		for (unsigned int i = 0; i < out[p].size(); i++)
    			c[++ci] = -out[p][i];
    		sort(c + 1,c + 1 + ci,cmp);
    		for (int i = 1; i <= ci; i++){
    			pu[i] = ++N,pd[i] = ++N;
    			su[i] = ++N,sd[i] = ++N;
    			if (i > 1){
    				build(pu[i - 1],pu[i],0);
    				build(pd[i - 1],pd[i],0);
    				build(su[i],su[i - 1],0);
    				build(sd[i],sd[i - 1],0);
    			}
    			if (c[i] >= 0) build(c[i],pu[i],0),build(c[i],su[i],0);
    			else c[i] *= -1,build(pd[i],c[i],0),build(sd[i],c[i],0);
    		}
    		for (int i = 1; i < ci; i++){
    			int tmp = T.dep[T.lca(pos[c[i]],pos[c[i + 1]])];
    			build(pu[i],pd[i + 1],tmp);
    			build(su[i + 1],sd[i],tmp);
    		}
    	}
    }
    void dijkstra(){
    	for (int i = 0; i <= N; i++) d[i] = INF,vis[i] = false;
    	for (unsigned int j = 0; j < out[1].size(); j++)
    		q.push(mp(d[out[1][j]] = 0,out[1][j]));
    	int u;
    	while (!q.empty()){
    		u = q.top().second; q.pop();
    		if (vis[u]) continue;
    		vis[u] = true;
    		Redge(u) if (!vis[to = ed[k].to] && d[to] > d[u] + ed[k].w + w[u]){
    			d[to] = d[u] + ed[k].w + w[u];
    			q.push(mp(d[to],to));
    		}
    	}
    }
    void print(){
    	for (int i = 2; i <= n; i++){
    		int ans = INF;
    		for (unsigned int j = 0; j < in[i].size(); j++)
    			ans = min(ans,d[in[i][j]] + w[in[i][j]]);
    		printf("%d
    ",ans);
    	}
    }
    int main(){
    	int Case = read();
    	while (Case--){
    		n = read(); m = read(); T.n = read(); init();
    		int a,b;
    		REP(i,m){
    			a = read(); b = read();
    			w[i] = read(); pos[i] = read();
    			out[a].push_back(i);
    			in[b].push_back(i);
    		}
    		N = m;
    		for (int i = 1; i < T.n; i++){
    			a = read(); b = read(); read();
    			T.build(a,b);
    		}
    		T.dfs(1);
    		Build();
    		dijkstra();
    		print();
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    解决express不是内部或外部命令
    spring ioc认识
    Filter编码过滤
    call、apply、bind
    js面向对象浅析
    由clientWidth到document
    401
    删除页面中Form下面隐藏的ViewStatue
    asp.net 下载
    day98
  • 原文地址:https://www.cnblogs.com/Mychael/p/9296099.html
Copyright © 2020-2023  润新知