题目链接
神仙题,马上把本憨批搞死的那种。我一开始想的是dijkstra套线段树。一个点代表一个区间,用区间查询来得出该点的dist值。结果完美的过了2个test(两个样例),然后wa在第3个test上。想到是因为区间与单点之间的转移问题,然后就没有然后了。
看题解真的给大佬跪了orz。打死我也想不到啊。我们先建一个长度n的线段树。然后建立两组节点in[i],out[i],线段树上的每一个节点分配一个in编号,一个out编号。一个(in)建边指向自己的两个孩子,一个(out)指向自己的祖先。权值均为0,然后,在此基础上再改咋建图,咋建图。最后跑一边dijkstra。
下面是ac代码:
// I am just a ping fan ren
//not a god, thanks.
#include <iostream>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <algorithm>
#include <cstdlib>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
const ll inf = 1e16;
int he[N], ver[N << 1], ne[N << 1];
bool vis[N];
ll e[N<<1];
ll dis[N];
int in[N<<1], out[N<<1];
int tot, n, m, s;
priority_queue<pair<ll, int> > q;
struct Node
{
int l, r;
}tr[N << 2];
void add(int x, int y, ll w)
{
ver[++tot] = y;
ne[tot] = he[x];
e[tot] = w;
he[x] = tot;
}
int cnt = 1;
void build(int p, int l, int r)
{
tr[p].l = l; tr[p].r = r;
if (l == r)
{
in[p] = out[p] = l;
return;
}
int mid = (l + r) >> 1;
in[p] = ++cnt;
out[p] = ++cnt;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
add(in[p], in[p << 1], 0);
add(in[p], in[p << 1 | 1], 0);
add(out[p << 1], out[p], 0);
add(out[p << 1 | 1], out[p], 0);
}
void buildeg(int p, int k, int l, int r, ll w, bool flag)
{
if (l <= tr[p].l && tr[p].r <= r)
{
if (flag) add(out[p], k, w);
else add(k, in[p], w);
return;
}
int mid = (tr[p].l + tr[p].r) >> 1;
if (l <= mid) buildeg(p << 1, k, l, r, w, flag);
if (r > mid) buildeg(p << 1 | 1, k, l, r, w, flag);
}
void dij()
{
for (int i = 0; i <= cnt; i++) dis[i] = inf;
dis[s] = 0;
q.push(make_pair(0, s));
while (q.size())
{
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = he[x]; i; i = ne[i])
{
int y = ver[i];
if (dis[y] > dis[x] + e[i])
{
dis[y] = dis[x] + e[i];
q.push(make_pair(-dis[y], y));
}
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &s);
cnt = n;
build(1, 1, n);
while (m--)
{
int op;
scanf("%d", &op);
int x, y, z;
ll w;
if (op == 1)
{
scanf("%d%d%lld", &x, &y, &z);
add(x, y, z);
}
else if (op == 2)
{
scanf("%d%d%d%lld", &x, &y, &z, &w);
buildeg(1, x, y, z, w, 0);
}
else
{
scanf("%d%d%d%lld", &x, &y, &z, &w);
buildeg(1, x, y, z, w, 1);
}
}
dij();
for (int i = 1; i <= n; i++)
{
if (dis[i] == inf) printf("-1");
else printf("%lld", dis[i]);
if (i != n) printf(" ");
}
printf("\n");
return 0;
}