卧薪尝胆,厚积薄发。
提高A组模拟 火车
Date: Sun Aug 19 15:01:18 CST 2018 In Category: NoCategory

Description:

有 $n$ 个城市构成一棵树,现在有火车在城市 $a$ ,需要经过 $m$ 个城市。每次行驶到第一个还没有经过的城市。求火车经过这m个城市后所经过的道路数量。
$1\le n \le 500000$

Solution:

求道路数量求出 $LCA$ 后树上差分,对于查询没有经过的城市,可以暴力把并查集向上合并,顺便跳过已经合并起来的链,由于每个点最多只合并一次,所以是 $O(n)$ 的。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 500010
struct edge
{
int to,nxt;
}e[MAXN << 1];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
++edgenum;e[edgenum].to = a;e[edgenum].nxt = lin[b];lin[b] = edgenum;
return;
}
int s[MAXN];
int f[MAXN][20];
int dep[MAXN];
bool v[MAXN];
int fa[MAXN];
int find(int x){return (fa[x] == x ? x : fa[x] = find(fa[x]));}
int LCA(int a,int b)
{
if(dep[a] < dep[b])swap(a,b);
for(int i = 19;i >= 0;--i)
if(dep[f[a][i]] >= dep[b])
a = f[a][i];
if(a == b)return a;
for(int i = 19;i >= 0;--i)
if(f[a][i] != f[b][i])
a = f[a][i],b = f[b][i];
a = f[a][0];b = f[b][0];
return a;
}
int main()
{
freopen("train.in","r",stdin);
freopen("train.out","w",stdout);
scanf("%d%d%d",&n,&m,&s[0]);
int a,b;
for(int i = 1;i < n;++i)
{
scanf("%d%d",&a,&b);
add(a,b);
}
for(int i = 1;i <= n;++i)fa[i] = i;
queue<int> q;
q.push(1);dep[1] = 1;
while(!q.empty())
{
int k = q.front();q.pop();
v[k] = true;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(v[e[i].to])continue;
f[e[i].to][0] = k;
dep[e[i].to] = dep[k] + 1;
q.push(e[i].to);
}
}
for(int k = 1;k <= 19;++k)
for(int i = 1;i <= n;++i)
f[i][k] = f[f[i][k - 1]][k - 1];
long long res = 0;
int k = s[0];
int cur = s[0];
for(int i = 1;i <= m;++i)
{
scanf("%d",&s[i]);
if(find(s[i]) == k)continue;
a = s[i];b = cur;
int lca = LCA(a,b);
res += dep[a] + dep[b] - 2 * dep[LCA(a,b)];
while(true)
{
if(dep[find(a)] > dep[lca])
{
fa[find(a)] = f[find(a)][0];
a = find(a);
}
else break;
}
while(true)
{
if(dep[find(b)] > dep[lca])
{
fa[find(b)] = f[find(b)][0];
b = find(b);
}
else break;
}
k = find(a);
cur = s[i];
}
cout << res << endl;
fclose(stdin);
fclose(stdout);
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡