[CF786B] Legacy

前言

第一道用线段树优化建边做的题,还是比较有记录意义的

当然也有对Rick姥爷的膜拜 orz

话说Rick为啥会给Morty留遗产

题目

洛谷

CF

讲解

首先操作一有手就行

问题是点连区间和区间连点的操作不好搞

区间?你会想到什么?

线段树!

直接让线段树上的点连边,表示点连区间和区间连点

但是我们发现一个问题,大区间可以由小区间组成,这会引起什么?

大区间可以走向单点,组成它的小区间也可以走向单点

单点可以走向小区间,单点也可以走向大区间

细品这两句话↑

所以我们需要两棵线段树分别维护走出去(从线段树走出去到单点,后者同理)和走进来

一切都变得简单了,注意long long和数组大小

我才不会用vector去卡空间,哼

代码

int head[MAXN * 9],tot;
struct edge
{
	int v,w,nxt;
}e[MAXN * 40];
void Add_Edge(int x,int y,int z)
{
	e[++tot].v = y;
	e[tot].w = z;
	e[tot].nxt = head[x];
	head[x] = tot;
}

int lc[MAXN * 9],rc[MAXN * 9],cnt;
int Build(int l,int r,int t)
{
	if(l == r) return l;
	int mid = (l+r) >> 1;
	int x = ++cnt;
	lc[x] = Build(l,mid,t);
	rc[x] = Build(mid+1,r,t);
	if(t == 1) Add_Edge(x,lc[x],0),Add_Edge(x,rc[x],0);//点连区间,往下走 
	else Add_Edge(lc[x],x,0),Add_Edge(rc[x],x,0);//区间连点,往上走 
	return x;
}
void update(int x,int l,int r,int ql,int qr,int ID,int val,int t)
{
	if(ql <= l && r <= qr)
	{
		if(t == 1) Add_Edge(ID,x,val);
		else Add_Edge(x,ID,val);
		return;
	}
	int mid = (l+r) >> 1;
	if(ql <= mid) update(lc[x],l,mid,ql,qr,ID,val,t);
	if(mid+1 <= qr) update(rc[x],mid+1,r,ql,qr,ID,val,t);
}

LL dis[MAXN * 9];
struct node
{
	int u;LL val;
	node(){}
	node(int u1,LL val1){
		u = u1;
		val = val1;
	}
	bool operator < (const node &px)const{
		return val > px.val;
	}
};
void dijkstra()
{
	for(int i = 1;i <= cnt;++ i) dis[i] = INF;
	priority_queue<node> q;
	q.push(node(S,dis[S] = 0));
	while(!q.empty())
	{
		node t = q.top(); q.pop();
		if(t.val > dis[t.u]) continue;
		for(int i = head[t.u]; i ;i = e[i].nxt)
			if(dis[e[i].v] > dis[t.u] + e[i].w)
				q.push(node(e[i].v,dis[e[i].v] = dis[t.u] + e[i].w));
	}
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read(); S = Read();
	cnt = n;
	rt1 = Build(1,n,1); rt2 = Build(1,n,2);
	while(m--)
	{
		int opt = Read(),u = Read(),l = Read(),r = Read();
		if(opt == 1) Add_Edge(u,l,r);
		else if(opt == 2) update(rt1,1,n,l,r,u,Read(),1);
		else update(rt2,1,n,l,r,u,Read(),2);
	}
	dijkstra();
	for(int i = 1;i <= n;++ i) Put(dis[i] == INF ? -1 : dis[i],' ');
	return 0;
}
原文地址:https://www.cnblogs.com/PPLPPL/p/13549628.html