卧薪尝胆,厚积薄发。
      
    
            SDOI2017 天才黑客
        
        
        Description:
给出一个带权有向图,每条边有一个口令,他们都在一棵
$trie$
树上,必须口令匹配才能经过,每次可以在某个节点花费
$LCP$
的代价换口令,求从
$1$
到其他所有点的最短路。
$1\leqslant n\leqslant 50000$
##Solution:
那个
$LCP$
的代价不太容易在最短路里体现,因此我们考虑把边拆成两个点,一个入点一个出点,之间连原来的边权,然后对于每个点,把所有进这个点的边的出点向所有离开这个点的边的入点连边,边权为
$LCP$
,然而这样建边边的个数还是
$O(m^2)$
的,我们可以把每条出边和入边分别按在
$trie$
树上的
$dfs$
序排序,然后两两之间求出
$height$
数组,那么两个字符串
$i,j$
的
$lcp$
就是区间
$\min height$
,那么对于一个
$i$
,我们一定可以用不超过
$h[i]$
的代价从
$i$
一侧的入点走到另一侧的出点,那么我们就可以使用一个叫做前后缀优化建图的技巧,也就是把图建成这样:
 
上面是入点,下面是出点,就可以实现一个前缀向一个后缀连边。
但是这样只能单向连,于是我们把一条边拆成两个入点两个出点,分别向前向后连,然后这四个点连成这样:
 
就行了。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
inline int rd()
{
	register int res = 0,f = 1;register char c = getchar();
	while(!isdigit(c)){if(c == '-')f = -1;c = getchar();}
	while(isdigit(c))res = (res << 1) + (res << 3) + c - '0',c = getchar();
	return res * f;
}
int n,m,p;
#define MAXN 50010
namespace DIJ
{
	#define MAXE (MAXN * 30)
	#define MAXP (MAXN * 5)
	struct edge
	{
		int to,nxt,v;
	}e[MAXE];
	int edgenum = 0;
	int lin[MAXP] = {0};
	void add(int a,int b,int c)
	{//cout << a << " -> " << b << " : " << c << endl;
		e[++edgenum] = (edge){b,lin[a],c};lin[a] = edgenum;
		return;
	}
	long long d[MAXP];
	bool vis[MAXP];
	int s;
	void dijkstra()
	{
		memset(vis,false,sizeof(vis));
		memset(d,0x3f,sizeof(d));d[s] = 0;
		priority_queue< pair<long long,int> > q;q.push(make_pair(0,s));
		while(!q.empty())
		{
			int k = q.top().second;q.pop();
			if(vis[k])continue;
			vis[k] = true;
			for(int i = lin[k];i != 0;i = e[i].nxt)
			{
				if(d[e[i].to] > d[k] + e[i].v)
				{
					d[e[i].to] = d[k] + e[i].v;
					q.push(make_pair(-d[e[i].to],e[i].to));
				}
			}
		}
		return;
	}
	void init()
	{
		edgenum = 0;
		memset(lin,0,sizeof(lin));
		return;
	}
}
namespace TRIE
{
	struct edge
	{
		int to,nxt;
	}e[MAXN];
	int edgenum = 0;
	int lin[MAXN] = {0};
	void add(int a,int b)
	{
		e[++edgenum] = (edge){b,lin[a]};lin[a] = edgenum;
		return;
	}
	int fa[MAXN],top[MAXN],dep[MAXN],son[MAXN],siz[MAXN];
	int dfn[MAXN],tot = 0;
	void dfs1(int k,int depth)
	{
		dep[k] = depth;
		siz[k] = 1;
		for(int i = lin[k];i != 0;i = e[i].nxt)
		{
			if(e[i].to != fa[k])
			{
				fa[e[i].to] = k;
				dfs1(e[i].to,depth + 1);
				siz[k] += siz[e[i].to];
				if(son[k] == 0 || siz[e[i].to] > siz[son[k]])son[k] = e[i].to;
			}
		}
		return;
	}
	void dfs2(int k,int tp)
	{
		top[k] = tp;
		dfn[k] = ++tot;
		if(son[k] == 0)return;
		dfs2(son[k],tp);
		for(int i = lin[k];i != 0;i = e[i].nxt)
		{
			if(e[i].to != fa[k] && e[i].to != son[k])
			{
				dfs2(e[i].to,e[i].to);
			}
		}
		return;
	}
	int LCA(int a,int b)
	{
		while(top[a] != top[b])
		{
			if(dep[top[a]] < dep[top[b]])swap(a,b);
			a = fa[top[a]];
		}
		return (dep[a] < dep[b] ? a : b);
	}
	int LCP(int a,int b){return dep[LCA(a,b)] - 1;}
	void init()
	{
		edgenum = tot = 0;
		memset(lin,0,sizeof(lin));
		memset(son,0,sizeof(son));
		memset(e,0,sizeof(e));
		return;
	}
}
int pcnt = 0;
namespace GRAPH
{
	struct edge
	{
		int to,nxt,v,d,ty,id;
	}e[MAXN << 1];
	int edgenum = 0;
	int lin[MAXN] = {0};
	void add(int a,int b,int l,int d,int id)
	{
		e[++edgenum] = (edge){b,lin[a],l,d,1,id};lin[a] = edgenum;
		e[++edgenum] = (edge){a,lin[b],l,d,0,id};lin[b] = edgenum;
		return;
	}
	void init()
	{
		edgenum = 0;
		memset(lin,0,sizeof(lin));
		memset(e,0,sizeof(e));
		return;
	}
}
int id[MAXN][5],idp[MAXN];
int s[MAXN],tp = 0;
int s1[MAXN],tp1 = 0;
int s2[MAXN],tp2 = 0;
bool cmp_es_dfn(int a,int b){return TRIE::dfn[GRAPH::e[a].d] < TRIE::dfn[GRAPH::e[b].d];}
void work()
{
	DIJ::init();TRIE::init();GRAPH::init();
	pcnt = 0;
	scanf("%d%d%d",&n,&m,&p);
	int a,b,c,d;
	for(int i = 1;i <= m;++i)
	{//cout << "###" << endl;
		a = rd();b = rd();c = rd();d = rd();
		GRAPH::add(a,b,c,d,i);
		for(int x = 1;x <= 4;++x)id[i][x] = ++pcnt;
		DIJ::add(id[i][1],id[i][2],c);
		DIJ::add(id[i][1],id[i][4],c);
		DIJ::add(id[i][3],id[i][2],c);
		DIJ::add(id[i][3],id[i][4],c);//cout << i << endl;
	}
	DIJ::s = ++pcnt;
	for(int i = GRAPH::lin[1];i != 0;i = GRAPH::e[i].nxt)
	{
		if(GRAPH::e[i].ty == 1)
		{
			DIJ::add(DIJ::s,id[GRAPH::e[i].id][1],0);
			DIJ::add(DIJ::s,id[GRAPH::e[i].id][3],0);
		}
	}
	for(int i = 2;i <= n;++i)idp[i] = ++pcnt;
	for(int k = 2;k <= n;++k)
	{
		for(int i = GRAPH::lin[k];i != 0;i = GRAPH::e[i].nxt)
		{
			if(GRAPH::e[i].ty == 0)
			{
				DIJ::add(id[GRAPH::e[i].id][2],idp[k],0);
				DIJ::add(id[GRAPH::e[i].id][4],idp[k],0);
			}
		}
	}
	for(int i = 1;i < p;++i)
	{
		scanf("%d%d%d",&a,&b,&c);
		TRIE::add(a,b);
	}
	TRIE::dfs1(1,1);TRIE::dfs2(1,1);//for(int i = 1;i <= p;++i)cout << TRIE::dfn[i] << " ";cout << endl;
	for(int k = 1;k <= n;++k)
	{
		tp = tp1 = tp2 = 0;//cout << " : " << k << endl;
		for(int i = GRAPH::lin[k];i != 0;i = GRAPH::e[i].nxt)
		{
			if(GRAPH::e[i].ty == 0)s1[++tp1] = i;
			if(GRAPH::e[i].ty == 1)s2[++tp2] = i;
			s[++tp] = i;
		}
		sort(s1 + 1,s1 + tp1 + 1,cmp_es_dfn);
		sort(s2 + 1,s2 + tp2 + 1,cmp_es_dfn);
		sort(s + 1,s + tp + 1,cmp_es_dfn);
		for(int i = 1;i < tp1;++i)DIJ::add(id[GRAPH::e[s1[i]].id][2],id[GRAPH::e[s1[i + 1]].id][2],0);
		for(int i = 1;i < tp2;++i)DIJ::add(id[GRAPH::e[s2[i]].id][1],id[GRAPH::e[s2[i + 1]].id][1],0);
		for(int i = 0,j = 1,x = 1;x < tp;++x)
		{
			while(i < tp1 && TRIE::dfn[GRAPH::e[s1[i + 1]].d] <= TRIE::dfn[GRAPH::e[s[x]].d])++i;
			while(j <= tp2 && TRIE::dfn[GRAPH::e[s2[j]].d] < TRIE::dfn[GRAPH::e[s[x + 1]].d])++j;
			if(1 <= i && i <= tp1 && j <= tp2)DIJ::add(id[GRAPH::e[s1[i]].id][2],id[GRAPH::e[s2[j]].id][1],TRIE::LCP(GRAPH::e[s[x]].d,GRAPH::e[s[x + 1]].d));
		}
		for(int i = 1;i < tp1;++i)DIJ::add(id[GRAPH::e[s1[i + 1]].id][4],id[GRAPH::e[s1[i]].id][4],0);
		for(int i = 1;i < tp2;++i)DIJ::add(id[GRAPH::e[s2[i + 1]].id][3],id[GRAPH::e[s2[i]].id][3],0);
		for(int i = 1,j = 0,x = 1;x < tp;++x)
		{
			while(j < tp2 && TRIE::dfn[GRAPH::e[s2[j + 1]].d] <= TRIE::dfn[GRAPH::e[s[x]].d])++j;
			while(i <= tp1 && TRIE::dfn[GRAPH::e[s1[i]].d] < TRIE::dfn[GRAPH::e[s[x + 1]].d])++i;
			if(1 <= j && j <= tp2 && i <= tp1)DIJ::add(id[GRAPH::e[s1[i]].id][4],id[GRAPH::e[s2[j]].id][3],TRIE::LCP(GRAPH::e[s[x]].d,GRAPH::e[s[x + 1]].d));
		}
	}
	DIJ::dijkstra();
	for(int i = 2;i <= n;++i)printf("%lld\n",DIJ::d[idp[i]]);
	return;
}
int main()
{
	int testcases = rd();
	while(testcases--)work();
	return 0;
}
        Copyright © 2020
        
          wjh15101051
        
      
      ღゝ◡╹)ノ♡
     Date: Thu Mar 28 20:46:16 CST 2019
          Date: Thu Mar 28 20:46:16 CST 2019
           In Category:
          In Category:
           In tag:
          In tag:
 
         Timeline
            Timeline
           About
            About
           Toolbox
            Toolbox
           Friends
              Friends