123789456ye

已AFO

[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;
}
posted @ 2020-03-27 10:17  123789456ye  阅读(69)  评论(0编辑  收藏  举报