【SDOI2017】天才黑客
这题太神了。
先模Claris 大神的题解。
首先我们要将边转换为点。如果暴力连边就会有\(m^2\)的边,于是我们考虑优化建图。
难点在于快速得到两个边的串的\(lcp\),也就是\(trie\)树上的\(lca\)。我们将一堆点按\(dfs\)序排序,然后\(a\)到\(b\)的\(lca\)就是排序后\(min\{lca(a,a+1),lca(a+1,a+2)...lca(b-1,b)\}\),这里的\(min\)是深度最小。
对于原图上的点\(i\),我们就将所有的边按\(dfs\)序拍好序,再复制一倍的虚点,相邻的实点和虚点连权值为\(0\)的边。每个实点向下一个点对应的虚点连权值为\(dep_{lca}\)的边。
然后还要反方向建相同的边,不过不能建在一张图上。
这道题中关于处理一堆点两两之间\(lca\)的方法值得掌握。
代码:
#include
#define ll long long
#define N 400005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,m,k;
int tot,TOT;
int w[N],t[N];
ll dis[N];
ll ans[N];
vectorst[N];
vectore[N];
struct road {
int to,next;
ll c;
}s[N*15];
int h[N],cnt;
void add(int i,int j,int c) {s[++cnt]=(road) {j,h[i],c};h[i]=cnt;}
int id,dfn[N];
void Init() {
cnt=0;
id=0;
memset(h,0,sizeof(h));
memset(t,0,sizeof(t));
memset(w,0,sizeof(w));
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=k;i++) e[i].clear();
for(int i=1;i<=n;i++) st[i].clear();
}
int dep[N];
int fa[N][20];
bool cmp(int a,int b) {return dfn[t[a]]dfn[t[b]];}
int lca(int a,int b) {
if(dep[a]=0;i--)
if(fa[a][i]&&dep[fa[a][i]]>=dep[b])
a=fa[a][i];
if(a==b) return a;
for(int i=16;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
void dfs(int v) {
dfn[v]=++id;
for(int i=1;i<=16;i++) fa[v][i]=fa[fa[v][i-1]][i-1];
for(int i=0;ia.d;}
};
priority_queueq;
bool vis[N];
void dij() {
memset(vis,0,sizeof(vis));
while(!q.empty()) {
node tem=q.top();q.pop();
int v=tem.v;
if(vis[v]) continue ;
vis[v]=1;
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(vis[to]) continue ;
if(dis[to]>dis[v]+s[i].c) {
dis[to]=dis[v]+s[i].c;
q.push(node(to,dis[to]));
}
}
}
}
int main() {
int T=Get();
while(T--) {
n=Get(),m=Get(),k=Get();
Init();
tot=m<<1,TOT=tot<<1;
int a,b,c,d;
for(int i=1;i<=m;i++) {
a=Get(),b=Get(),c=Get(),d=Get();
t[i]=t[i+m]=d;
w[i]=w[i+TOT]=c;
st[b].push_back(i);
st[a].push_back(i+m);
add(i+m+tot,i,w[i]);
add(i+m+tot+TOT,i,w[i]);
add(i+m+tot,i+TOT,w[i]);
add(i+m+tot+TOT,i+TOT,w[i]);
}
for(int i=1;im) {
dis[st[1][i]-m]=dis[st[1][i]-m+TOT]=w[st[1][i]-m];
q.push(node(st[1][i]-m,w[st[1][i]-m]));
q.push(node(st[1][i]-m+TOT,w[st[1][i]-m]));
}
}
dij();
memset(ans,0x3f,sizeof(ans));
for(int i=1;i<=n;i++) {
for(int j=0;j