[CF768B] Legacy
题面:Luogu
题解:线段树优化连边+最短路
像这种区间连边的问题我们考虑直接上线段树优化(因为一条一条连复杂度太高了)
标准模板就是建两颗线段树,一颗入一颗出
入的树父亲向儿子连边表示能到父亲必定能到儿子
出的树儿子向父亲连边表示能从儿子出来必定也能从父亲出来
以上连边边权为0
给的边从出树的对应区间向超级点连边,超级点向入树对应区间连边,两条边边权之和为给定边权
不过这个题比较简单,直接对应连边即可,没有区间连区间
这是我对着题解写的,下次去蒯一个码风好看一点的感觉这个并不是很好
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T& x)
{
x = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 100005
#define ls rt<<1
#define rs rt<<1|1
struct Edge
{
int fr, to, val;
}eg[maxn * 20];
int head[maxn << 2], edgenum;
inline void add(int fr, int to, int val)
{
eg[++edgenum] = { head[fr],to,val };
head[fr] = edgenum;
}
int in[maxn << 2], out[maxn << 2], cnt;
void build(int rt, int l, int r)
{
if (l == r)
{
in[rt] = out[rt] = l;
return;
}
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
out[rt] = ++cnt; in[rt] = ++cnt;
add(out[ls], out[rt], 0), add(in[rt], in[ls], 0);
add(out[rs], out[rt], 0), add(in[rt], in[rs], 0);
}
void update_in(int rt, int l, int r, int fr, int to, int from, int cost)
{
if (fr <= l && to >= r)
{
add(from, in[rt], cost);
return;
}
int mid = (l + r) >> 1;
if (fr <= mid) update_in(ls, l, mid, fr, to, from, cost);
if (to > mid) update_in(rs, mid + 1, r, fr, to, from, cost);
}
void update_out(int rt, int l, int r, int fr, int to, int from, int cost)
{
if (fr <= l && to >= r)
{
add(out[rt], from, cost);
return;
}
int mid = (l + r) >> 1;
if (fr <= mid) update_out(ls, l, mid, fr, to, from, cost);
if (to > mid) update_out(rs, mid + 1, r, fr, to, from, cost);
}
#define mp make_pair
#define pa pair<long long,int>
priority_queue<pa, vector<pa>, greater<pa> >q;
long long dis[maxn * 10], inf; int vis[maxn * 10];
void dijskra(int s)
{
memset(dis, 0x3f, sizeof(dis)); inf = dis[s];
dis[s] = 0; q.push(mp(dis[s], s));
while (!q.empty())
{
int tp = q.top().second; q.pop();
if (vis[tp]) continue; vis[tp] = 1;
for (int i = head[tp]; i; i = eg[i].fr)
if (dis[eg[i].to] > dis[tp] + eg[i].val)
dis[eg[i].to] = dis[tp] + eg[i].val, q.push(mp(dis[eg[i].to], eg[i].to));
}
}
int main()
{
int n, q, s;
read(n), read(q), read(s);
cnt = n; build(1, 1, n);//注意这个写法要写cnt=n
for (int i = 1, op, fr, l, r, z; i <= q; ++i)
{
read(op);
if (op == 1)
{
read(fr), read(l), read(z);
add(fr, l, z);
}
else if (op == 2)
{
read(fr), read(l), read(r), read(z);
update_in(1, 1, n, l, r, fr, z);
}
else
{
read(fr), read(l), read(r), read(z);
update_out(1, 1, n, l, r, fr, z);
}
}
dijskra(s);
for (int i = 1; i <= n; ++i) printf("%lld ", dis[i] == inf ? -1 : dis[i]);
return 0;
}
一切伟大的行动和思想,都有一个微不足道的开始。
There is a negligible beginning in all great action and thought.
There is a negligible beginning in all great action and thought.