B - Legacy

CodeForces - 787D

这个题目开始看过去还是很简单的,就是一个最短路,但是这个最短路的建图没有那么简单,因为直接的普通建图边太多了,肯定会超时的,所以要用线段树来优化建图。

这个题目我一开始也没想到,不知道怎么用线段树优化,然后看了一下题解,豁然开朗。

首先建两棵线段树,有点类似拆点,然后其中一颗从下往上建图A,一颗从上往下建图B。

从上往下建图的每一个叶子节点连着从上往下建图的每一个叶子节点。 权值都是0

p==1 那就直接是B 的叶子节点连着A 的叶子节点,权值为w

p==2 那就是A的叶子节点v 连着B的这个区间的节点

p==3 那就是A 的区间节点连着B的叶子节点v

起点在A这颗树的地球位置的根节点。

建完图之后就是跑一个最短路。

这个是大概思路,但是怎么写呢,

首先肯定是建树,建树的过程中建图,而且还要记录每一个节点的编号,并且记录每一个叶子节点的编号。

然后就是根据要求建图如果是区间就要进行查找这个区间节点就可以了。

接下来就是考验码力的时候了。

这个题目想清楚之后就不是很难写了,只是这个空间要注意,因为这个wa了三发。

这个方法要学习学习。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 2e5 + ;
int numa[maxn * ], numb[maxn * ], lefta[maxn * ], leftb[maxn * ];
ll d[maxn*], tot;
int n, m;
bool vis[maxn*];
struct edge {
int from, to, dist;
edge(int from=, int to=, int dist=) :from(from), to(to), dist(dist) {}
};
struct heapnode {
int u;
ll d;
heapnode(ll d=, int u=) : d(d), u(u) {}
bool operator<(const heapnode &a) const {
return a.d < d;
}
}; vector<edge> vec;
vector<int> g[maxn*]; void add(int u,int v,int w)
{
vec.push_back(edge(u, v, w));
int m = vec.size();
g[u].push_back(m - );
// printf("u=%d v=%d w=%d\n", u, v, w);
} void dijkstra(int s) {
priority_queue<heapnode>que;
for (int i = ; i <= tot; i++) d[i] = inf64;
d[s] = ;
memset(vis, , sizeof(vis));
que.push(heapnode(, s));
while (!que.empty()) {
heapnode x = que.top(); que.pop();
int u = x.u;
if (vis[u]) continue;
vis[u] = ;
for (int i = ; i < g[u].size(); i++) {
edge &e = vec[g[u][i]];
// printf("u=%d e.to=%d e.dist=%d\n", u, e.to, e.dist);
// printf("d[%d]=%lld d[%d]=%lld\n", u, d[u], e.to, d[e.to]);
if (d[e.to] > d[u] + e.dist) {
// printf("ww\n");
d[e.to] = d[u] + e.dist;
que.push(heapnode(d[e.to], e.to));
}
}
}
for(int i=;i<=n;i++)
{
if (d[lefta[i]] >= inf64) printf("-1 ");
else printf("%lld ", d[lefta[i]]);
}
} void builda(int id,int l,int r)
{
numa[id] = ++tot;
int mid = (l + r) >> ;
if(l==r)
{
lefta[l] = tot;
return;
}
builda(id << , l, mid);
builda(id << | , mid + , r);
add(numa[id << ], numa[id], );
add(numa[id << | ], numa[id], );
} void buildb(int id,int l,int r)
{
numb[id] = ++tot;
int mid = (l + r) >> ;
if(l==r)
{
leftb[l] = tot;
return;
}
buildb(id << , l, mid);
buildb(id << | , mid + , r);
add(numb[id], numb[id << ], );
add(numb[id], numb[id << | ], );
} void build3(int n)
{
for (int i = ; i <= n; i++) add(leftb[i], lefta[i], );
} void updatea(int id,int l,int r,int x,int y,int b,int w)
{
if (x <= l && y >= r) {
add(numa[id], b, w);
return;
}
int mid = (l + r) >> ;
if (x <= mid) updatea(id << , l, mid, x, y, b, w);
if (y > mid) updatea(id << | , mid + , r, x, y, b, w);
} void updateb(int id,int l,int r,int x,int y,int a,int w)
{
if(x<=l&&y>=r)
{
add(a, numb[id], w);
return;
}
int mid = (l + r) >> ;
if (x <= mid) updateb(id << , l, mid, x, y, a, w);
if (y > mid) updateb(id << | , mid + , r, x, y, a, w);
} int main()
{
int s;
tot = ;
scanf("%d%d%d", &n, &m, &s);
builda(, , n), buildb(, , n), build3(n);
while(m--)
{
int opt, u, v, l, r, w;
scanf("%d", &opt);
if (opt == ) {
scanf("%d%d%d", &u, &v, &w);
add(lefta[u], leftb[v], w);
}
if(opt==)
{
scanf("%d%d%d%d", &u, &l, &r, &w);
updateb(, , n, l, r, lefta[u], w);
}
if(opt==)
{
scanf("%d%d%d%d", &u, &l, &r, &w);
updatea(, , n, l, r, leftb[u], w);
}
}
dijkstra(lefta[s]);
return ;
}

线段树+最短路

04-21 11:08
查看更多