4227: 城市
Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 44 Solved: 16
[Submit][Status][Discuss]
Description
A国是一个拥有n个城市的国家,其中城市s是A国的首都。
A国还有m条道路,每条道路连着两个不同的城市,但是一对城市间可能有多条道路。每一条道路都有它的长度,一条道路的通行时间与一条道路的长度成正比。
你作为A国的统治者,设计出了一种统计城市重要程度的方法:
1、一条道路的重要度为:在这条道路不能使用的情况下,到首都s的最短时间会变长的城市的数目。
2、一个城市的重要度为:以它作为一端的所有道路的重要度的和。
现在,你知道了A国的道路连接情况,你需要计算出每一个城市的重要度。
Input
第一行,两个整数n,m,表示有A国有n个城市及m条道路。
第2~m+1行,每行三个整数u,v,l,描述了一条道路的两个端点城市及长度。
第m+2行,一个整数s,表示A国首都的编号
Output
n行,每行一个整数,第i行为编号i的城市的重要度。
Sample Input
4 4
1 2 3
2 3 4
3 4 5
4 1 2
1
Sample Output
2
1
0
1
HINT
100%的数据,1<=n<=100000,1<=m<=200000,1<=l<=10^8
Source
我发现了一个非常神奇的方法做这道题
先考虑一个问题:如何计算缺少点u时,最短路径会边长的点数(设为ans[u])
首先先把最短路径树跑出来,然后我们按顺序加边进去
u显然只会对他的父亲的祖先的交集的答案产生贡献
那么我们一边加边的时候一边维护树上lca倍增(dep要用lct维护),同时如果加到一个点有父亲,那么把当前点和这个点之前的父亲取一个lca,作为这个点的新的父亲
然后这样瞎搞一波可以把ans数组处理出来
接下来考虑如何转换成边的答案
考虑点u的ans会对父边产生贡献,必须满足两个条件:在最短路径树上只有一个父亲(且只有一条边到父亲);在最短路径树上u的父亲也是构造出的树上的父亲。
然后瞎搞一波计算出答案就好了
==================================
upd.2018/7/30:原来这东西叫支配树。。。。。
代码:
#include<queue>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const LL INF = 100000000000000000LL;
const int maxn = 100010;
struct data{
int pri,id;
bool operator < (const data &B) const
{
return pri > B.pri;
}
};
struct edge{
int to; LL w;
};
vector<edge> e[maxn];
vector<int> ne[maxn],c[maxn];
priority_queue<data> Q;
int n,m,s,ans[maxn],Siz[maxn],cnt[maxn],cntfa[maxn],allfa[maxn];
int fa[maxn],ch[maxn][2],siz[maxn],prefa[maxn];
int pa[maxn][25],ln[maxn];
int done[maxn],q[maxn];
LL dis[maxn];
inline LL getint()
{
LL ret = 0,f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret * f;
}
inline void init()
{
for (int i = 1; i <= n; i++) dis[i] = INF;
Q.push((data){dis[s] = 0,s});
while (!Q.empty())
{
int u = Q.top().id;
Q.pop();
if (done[u]) continue;
done[u] = 1;
for (int i = 0; i < e[u].size(); i++)
{
int v = e[u][i].to; LL w = e[u][i].w;
if (dis[u] + w < dis[v])
Q.push((data){dis[v] = dis[u] + w,v});
}
}
for (int u = 1; u <= n; u++)
{
for (int i = 0; i < e[u].size(); i++)
{
int v = e[u][i].to; LL w = e[u][i].w;
if (dis[u] + w == dis[v])
ne[u].push_back(v) , allfa[v] = ++cntfa[v];
}
}
int p = -1;
for (int i = 1; i <= n; i++)
{
if ((i & -i) == i) p++;
ln[i] = p;
}
for (int i = 1; i <= n; i++) siz[i] = 1;
}
inline void maintain(int o)
{
siz[o] = siz[ch[o][0]] + siz[ch[o][1]] + 1;
}
inline void rotate(int x)
{
int o = fa[x],y = fa[o];
int d = ch[o][1] == x ? 0 : 1;
ch[o][d ^ 1] = ch[x][d]; maintain(o);
if (ch[x][d]) fa[ch[x][d]] = o;
ch[x][d] = o; maintain(x);
fa[o] = x; fa[x] = y;
swap(prefa[o],prefa[x]);
if (y) ch[y][ch[y][1] == o] = x , maintain(y);
}
inline void splay(int x)
{
for (int y = fa[x]; y; rotate(x) , y = fa[x])
if (fa[y]) rotate((ch[y][1] == x) ^ (ch[fa[y]][1] == y) ? x : y);
}
inline void access(int x)
{
for (int u = x,v = 0; u; v = u,u = prefa[u])
{
splay(u);
if (ch[u][1]) prefa[ch[u][1]] = u , fa[ch[u][1]] = 0;
if (v) prefa[v] = 0 , fa[v] = u;
ch[u][1] = v;
maintain(u);
}
}
inline int getdep(int x)
{
access(x);
splay(x);
return siz[ch[x][0]] + 1;
}
inline void cut(int u)
{
access(u);
splay(u);
fa[ch[u][0]] = 0;
ch[u][0] = 0;
maintain(u);
}
inline void join(int u,int v)
{
access(u);
splay(u);
fa[v] = u;
ch[u][1] = v;
maintain(u);
}
inline int lca(int u,int v)
{
int x = getdep(u),y = getdep(v);
if (x < y) {swap(u,v); swap(x,y);}
for (int j = ln[x]; j >= 0; j--)
if (x - (1 << j) >= y)
{
u = pa[u][j];
x -= 1 << j;
}
if (u == v) return u;
for (int j = ln[x]; j >= 0; j--)
if (pa[u][j] != pa[v][j])
{
u = pa[u][j];
v = pa[v][j];
}
return pa[u][0];
}
inline void update(int u)
{
for (int i = 1; i <= 20; i++)
pa[u][i] = pa[pa[u][i - 1]][i - 1];
}
inline void bfs()
{
int head = 0,tail = 0;
q[++tail] = s;
while (head < tail)
{
int u = q[++head];
for (int i = 0; i < ne[u].size(); i++)
{
int v = ne[u][i];
int test;
if (head == 2416 && i == 2)
test = 1;
if (!pa[v][0])
{
pa[v][0] = u;
join(u,v);
update(v);
}
else
{
pa[v][0] = lca(u,pa[v][0]);
cut(v); join(pa[v][0],v);
update(v);
}
cntfa[v]--;
if (!cntfa[v])
q[++tail] = v;
}
}
}
inline void dp(int u)
{
for (int i = 0; i < c[u].size(); i++)
{
int v = c[u][i];
dp(v);
Siz[u] += Siz[v];
}
Siz[u]++;
}
inline void cal(int u)
{
for (int i = 0; i < ne[u].size(); i++)
{
int v = ne[u][i];
if (pa[v][0] != u) continue;
if (allfa[v] > 1) continue;
ans[u] += Siz[v];
ans[v] += Siz[v];
}
}
int main()
{
#ifdef AMC
freopen("AMC1.txt","r",stdin);
freopen("AMC2.txt","w",stdout);
#endif
n = getint(); m = getint();
for (int i = 1; i <= m; i++)
{
int u = getint(),v = getint(),w = getint();
e[u].push_back((edge){v,w});
e[v].push_back((edge){u,w});
}
s = getint();
init();
bfs();
for (int i = 1; i <= n; i++)
c[pa[i][0]].push_back(i);
dp(s);
for (int i = 1; i <= n; i++) cal(i);
for (int i = 1; i <= n; i++)
printf("%d\n",ans[i]);
return 0;
}