您的位置:首页 > 其它

AcDream 1415 Important Roads 解题报告(最短路 + 线段树)

2014-10-04 19:27 363 查看


Important Roads

Special JudgeTime Limit: 20000/10000MS (Java/Others)Memory
Limit: 128000/64000KB (Java/Others)

SubmitStatisticNext
Problem


Problem Description

      The city where Georgie lives has n junctions some of which are connected by bidirectional roads.

      Every day Georgie drives from his home to work and back. But the roads in the city where Georgie lives are very bad, so they are very often closed for repair. Georgie noticed that
when some roads are closed he still can get from home to work in the same time as if all roads were available.
      But there are such roads that if they are closed for repair the time Georgie needs to get from home to work increases, and sometimes Georgie even cannot get to work by a car any more. Georgie calls such roads
important.

      Help Georgie to find all important roads in the city.


Input

      The first line of the input file contains n and m — the number of junctions and roads in the city where Georgie lives, respectively (2 ≤ n ≤ 20 000, 1 ≤ m ≤ 100 000). Georgie lives at the junction 1 and works at
the junction n.
      The following m lines contain information about roads. Each road is specified by the junctions it connects and the time Georgie needs to drive along it. The time to drive along the road is positive and doesn’t exceed
100 000. There can be several roads between a pair of junctions, but no road connects a junction to itself. It is guaranteed that if all roads are available, Georgie can get from home to work.


Output

      Output l — the number of important roads — at the first line of the output file. The second line must contain l numbers, the numbers of important roads. Roads are numbered from 1 to m as they are given in the input file.


Sample Input

6 7
1 2 1
2 3 1
2 5 3
1 3 2
3 5 1
2 4 1
5 6 2



Sample Output

2
5 7


    解题报告: 队友说这题是求最短路,然后求桥。

    当然,图论我不太熟,比赛的时候直接用最短路和线段树做了。

    首先求出每个点到起点的最短距离,到终点的最短距离。然后如果dis(sta, u) + len(u, v) + dis(v, end) = shortPath,那么我们可以确定这条边在最短路上。

    接下来我们要确定u,v这段路径是否是重要的。如果重要,那么从dis(sta, u)开始,到dis(sta, v),这段路必然是唯一的。如果中间有其他重复覆盖了,那么这两条路都不是重要的。我们用线段树完成这个操作。因为距离比较大,所以需要离散化处理。当u,v这条边覆盖了[a, b]这段路程时,我们在线段树上将[a, b-1]区间置为这条边的id。第二次我们判断[a, b-1]是否都是被置为这条边的id,如果不是,那么这条边就不是重要的。

    代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iomanip>
#include <cassert>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define travel(e, u) for(int e = u, v = vv[u]; e; e = nxt[e], v = vv[e])
#define bit(n) (1LL<<(n))
#define clr(a, b) memset((a), b, sizeof(a))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{
#ifdef ACM
freopen("in.txt", "r", stdin);
#endif // ACM

work();
return 0;
}

void scanf(int & x, char ch = 0)
{
while((ch=getchar()) < '0' || ch > '9');

x = ch - '0';
while((ch=getchar()) >= '0' && ch <= '9') x = x * 10 + ch - '0';
}

/***************************************************************************************/

const int maxv = 20010;
const int maxe = 200010;

int n, m;
int edge[maxv], ecnt;
int nxt[maxe], vv[maxe], ww[maxe], eid[maxe];

int dSta[maxv], dEnd[maxv];
bool vis[maxv];
bool evis[maxe];

int g[maxe];
int pos[maxv];

int ma[maxv << 2];
int mi[maxv << 2];
int co[maxv << 2];

void init()
{
ecnt = 2;
clr(edge, 0);
}

void addEdge(int u, int v, int w, int id, int first[])
{
nxt[ecnt] = first[u], vv[ecnt] = v, ww[ecnt] = w, eid[ecnt] = id, first[u] = ecnt++;
}

struct Node
{
int u, d;
Node(int u = 0, int d = 0) : u(u), d(d) {}
bool operator<(const Node & cmp) const
{
return d > cmp.d;
}
} x, y;

void getShortPath(int sta, int arr[])
{
clr(vis, 0);

priority_queue<Node> que;
que.push(Node(sta, 0));

while(que.size())
{
x = que.top();
que.pop();

if(vis[x.u]) continue;
vis[x.u] = true, arr[x.u] = x.d;

travel(e, edge[x.u]) if(!vis[v])
que.push(Node(v, x.d + ww[e]));
}
}

#define lson l, m, pos<<1
#define rson m+1, r, pos<<1|1
#define ls (pos<<1)
#define rs (pos<<1|1)
#define mid ((l+r)/2)
#define rt 0, tot, 1

void updateFather(int pos)
{
ma[pos] = max(ma[ls], ma[rs]);
mi[pos] = min(mi[ls], mi[rs]);
}

void updateSon(int pos)
{
if(co[pos])
{
co[ls] = ma[ls] = mi[ls] = co[pos];
co[rs] = ma[rs] = mi[rs] = co[pos];
co[pos] = 0;
}
}

void update(int L, int R, int v, int l, int r, int pos)
{
if(L<=l && r<=R)
{
co[pos] = ma[pos] = mi[pos] = v;
return;
}

updateSon(pos);
int m = mid;
if(L<=m) update(L, R, v, lson);
if(m <R) update(L, R, v, rson);
updateFather(pos);
}

int Mi, Ma;
void qry(int L, int R, int l, int r, int pos)
{
if(L<=l && r<=R)
{
Mi = min(Mi, mi[pos]);
Ma = max(Ma, ma[pos]);
return;
}

updateSon(pos);
int m = mid;
int ret = 0;
if(L<=m) qry(L,R,lson);
if(m< R) qry(L,R,rson);
}

void work()
{
while(scanf("%d%d", &n, &m) == 2)
{
init();

fff(i, 1, m)
{
int u, v, w;
scanf(u), scanf(v), scanf(w);
addEdge(u, v, w, i, edge);
addEdge(v, u, w, i, edge);
}

getShortPath(1, dSta);
getShortPath(n, dEnd);
int shrt = dEnd[1];

int tot = 0;
fff(i, 1, n)
g[tot++] = dSta[i];

sort(g, g + tot);
tot = unique(g, g + tot) - g;

fff(i, 1, n)
pos[i] = lower_bound(g, g+tot, dSta[i]) - g;

clr(ma, 0);
clr(mi, 0x7f);
clr(co, 0);
clr(evis, 0);
fff(u, 1, n)
{
travel(e, edge[u]) if(u != v && dSta[u] + ww[e] == shrt - dEnd[v])
{
int L = pos[u];
int R = pos[v] - 1;

evis[eid[e]] = true;
update(L, R, eid[e], 0, tot, 1);
}
}

fff(u, 1, n)
{
travel(e, edge[u]) if(u != v && dSta[u] + ww[e] == shrt - dEnd[v])
{
int L = pos[u];
int R = pos[v] - 1;

Ma = 0, Mi = 0x7f7f7f7f;
qry(L, R, 0, tot, 1);

if(Ma != eid[e] || Mi != eid[e])
evis[eid[e]] = false;

update(L, R, eid[e], 0, tot, 1);
}
}

int ans = 0;
fff(i, 1, m) if(evis[i])
g[ans++] = i;
printf("%d\n", ans);
if(ans) printf("%d", g[0]);
fff(i, 1, ans-1) printf(" %d", g[i]);
puts("");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: