CF786B Legacy 线段树优化建图

传送门

文章目录

题意:

实现如下连边后跑最短路。
在这里插入图片描述

思路:

优化建图板子题,优化思路就是将区间分割成若干个线段树上的线段,与线段树分治有点类似,由于有点向区间也有区间向点的边,那么我们需要建两颗线段树,点向区间的树是自顶向下连边,区间向点的是自底向上连边,最后两棵树的最后一层需要与原来的 n n n个点连双向(未经说明都是单向边),比如下面这个图(盗用了日报的图)
在这里插入图片描述
让后我们就按照图来建边就好啦,我这里第一颗编号是 [ 1 , 4 ∗ n ] [1,4*n] [1,4n],第二棵编号是 [ 4 ∗ n + 1 , 8 ∗ n ] [4*n+1,8*n] [4n+1,8n],绿色点是 [ 8 ∗ n + 1 , 9 ∗ n ] [8*n+1,9*n] [8n+1,9n]
当然可以舍去绿色的点,直接以线段树叶子节点为绿色的点,下面也给出代码了,只需要记一下 l e a f [ i ] leaf[i] leaf[i]即可。

// Problem: B. Legacy
// Contest: Codeforces - Codeforces Round #406 (Div. 1)
// URL: https://codeforces.com/problemset/problem/786/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;

//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<LL,int> PII;

const int N=900200,M=N*40,mod=1e9+7,INF=0x3f3f3f3f;
const LL inf=0x3f3f3f3f3f3f3f3f;
const double eps=1e-6;

int n,q,s,b1,b2;
int e[M],ne[M],w[M],h[N],idx;
LL dis[N];
bool st[N];
//第一颗线段树1-4*n 第二棵4*n+1-8*n 点8*n+1-9*n

void add(int a,int b,int c) {
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void build(int u,int l,int r) {
	if(l==r) {
		add(u,l+8*n,0); add(l+8*n,u,0);
		add(u+4*n,l+8*n,0); add(l+8*n,u+4*n,0);
		return;
	}
	add(u,u*2,0); add(u,u*2+1,0);
	add(u*2+4*n,u+4*n,0); add(u*2+1+4*n,u+4*n,0);
	int mid=(l+r)>>1;
	build(u<<1,l,mid); build(u<<1|1,mid+1,r);
}

void change1(int u,int l,int r,int ql,int qr,int st,int cs) {
	if(ql<=l&&qr>=r) {
		add(st+8*n,u,cs);
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) change1(u<<1,l,mid,ql,qr,st,cs);
	if(qr>mid) change1(u<<1|1,mid+1,r,ql,qr,st,cs);
}

void change2(int u,int l,int r,int ql,int qr,int st,int cs) {
	if(ql<=l&&qr>=r) {
		add(u+4*n,st+8*n,cs);
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) change2(u<<1,l,mid,ql,qr,st,cs);
	if(qr>mid) change2(u<<1|1,mid+1,r,ql,qr,st,cs);
}

void dijkstra() {
	priority_queue<PII,vector<PII>,greater<PII> >q; q.push({0ll,s+8*n});
	memset(dis,0x3f3f3f3f,sizeof(dis));
	dis[s+8*n]=0;
	while(q.size()) {
		PII u=q.top(); q.pop();
		if(st[u.Y]) continue;
		st[u.Y]=1;
		for(int i=h[u.Y];~i;i=ne[i]) {
			int j=e[i];
			if(dis[j]>dis[u.Y]+w[i]) {
				dis[j]=dis[u.Y]+w[i];
				q.push({dis[j],j});
			}
		}
	}
	for(int i=1;i<=n;i++) printf("%lld ",dis[i+8*n]==inf? -1:dis[i+8*n]);
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

	memset(h,-1,sizeof(h));
	cin>>n>>q>>s;
	build(1,1,n);
	while(q--) {
		int op,v,l,r,c;
		scanf("%d",&op);
		if(op==1) {
			scanf("%d%d%d",&l,&r,&c);
			add(l+8*n,r+8*n,c);
		}
		else if(op==2) {
			scanf("%d%d%d%d",&v,&l,&r,&c);
			change1(1,1,n,l,r,v,c);
		}
		else {
			scanf("%d%d%d%d",&v,&l,&r,&c);
			change2(1,1,n,l,r,v,c);
		}
	}
	dijkstra();

	




	return 0;
}
/*

*/









// Problem: B. Legacy
// Contest: Codeforces - Codeforces Round #406 (Div. 1)
// URL: https://codeforces.com/problemset/problem/786/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;

//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<LL,int> PII;

const int N=800200,M=N*20,mod=1e9+7,INF=0x3f3f3f3f;
const LL inf=0x3f3f3f3f3f3f3f3f;
const double eps=1e-6;

int n,q,s,b1,b2;
int e[M],ne[M],w[M],h[N],idx;
int leaf[N];
LL dis[N];
bool st[N];
//第一颗线段树1-4*n 第二棵4*n+1-8*n 

void add(int a,int b,int c) {
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void build(int u,int l,int r) {
	if(l==r) {
		leaf[l]=u;
		return;
	}
	int mid=(l+r)>>1;
	add(u,u*2,0); add(u,u*2+1,0);
	add(u*2+4*n,u+4*n,0); add(u*2+1+4*n,u+4*n,0);
	build(u<<1,l,mid); build(u<<1|1,mid+1,r);
}

void change1(int u,int l,int r,int ql,int qr,int st,int w) {
	if(ql<=l&&qr>=r) {
		add(st,u,w);
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) change1(u<<1,l,mid,ql,qr,st,w);
	if(qr>mid) change1(u<<1|1,mid+1,r,ql,qr,st,w);
}

void change2(int u,int l,int r,int ql,int qr,int st,int w) {
	if(ql<=l&&qr>=r) {
		add(u+4*n,st,w);
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) change2(u<<1,l,mid,ql,qr,st,w);
	if(qr>mid) change2(u<<1|1,mid+1,r,ql,qr,st,w);
}

void dijkstra() {
	memset(dis,0x3f3f3f3f,sizeof(dis));
	priority_queue<PII,vector<PII>,greater<PII>>q;
	q.push({s,leaf[s]}); dis[leaf[s]]=0;
	while(q.size()) {
		PII u=q.top(); q.pop();
		if(st[u.Y]) continue;
		st[u.Y]=1;
		for(int i=h[u.Y];~i;i=ne[i]) {
			int j=e[i];
			if(dis[j]>dis[u.Y]+w[i]) {
				dis[j]=dis[u.Y]+w[i];
				q.push({dis[j],j});
			}
		}
	}
	for(int i=1;i<=n;i++) printf("%lld ",dis[leaf[i]]==inf? -1:dis[leaf[i]]);
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

	memset(h,-1,sizeof(h));
	cin>>n>>q>>s;
	build(1,1,n);
	for(int i=1;i<=n;i++) add(leaf[i],leaf[i]+4*n,0),add(leaf[i]+4*n,leaf[i],0);
	while(q--) {
		int op,v,l,r,c;
		scanf("%d",&op);
		if(op==1) {
			scanf("%d%d%d",&l,&r,&c);
			add(leaf[l],leaf[r],c);
		}
		else if(op==2) {
			scanf("%d%d%d%d",&v,&l,&r,&c);
			change1(1,1,n,l,r,leaf[v],c);
		}
		else {
			scanf("%d%d%d%d",&v,&l,&r,&c);
			change2(1,1,n,l,r,leaf[v],c);
		}
	}
	dijkstra();
	




	return 0;
}
/*

*/









  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值