1. 程式人生 > 實用技巧 >習題:Legacy(線段樹優化建圖)

習題:Legacy(線段樹優化建圖)

題目

傳送門

思路

類似於建虛點

注意到題目中的操作區間都是連續的,用線段樹來優化建圖即可

程式碼

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node_tre
{
	int l;
	int r;
}tre[2][400005];//0表示出,1表示入
struct node_g
{
	int e;
	long long w;
	friend bool operator < (const node_g &a,const node_g &b)
	{
		return a.w>b.w;
	}
};
int n,m,s;
int opt;
int u,l,r,w;
bool vis[900015];
long long dis[900005];
vector<node_g> g[900015];
priority_queue<node_g> q;
void build(int l,int r,int k)
{
	tre[0][k].l=tre[1][k].l=l;
	tre[0][k].r=tre[1][k].r=r; 
	if(l==r)
	{
		g[l].push_back((node_g){n+k,0});
		g[5*n+k].push_back((node_g){l,0});
		return;
	}
	g[n+(k<<1)].push_back((node_g){n+k,0});
	g[n+(k<<1|1)].push_back((node_g){n+k,0});
	g[5*n+k].push_back((node_g){5*n+(k<<1),0});
	g[5*n+k].push_back((node_g){5*n+(k<<1|1),0});
	int mid=(l+r)>>1;
	build(l,mid,k<<1);
	build(mid+1,r,k<<1|1);
}
void change(int l,int r,int st,long long w,int opt,int k)
{
	if(l>tre[opt][k].r||tre[opt][k].l>r)
		return;
	if(l<=tre[opt][k].l&&tre[opt][k].r<=r)
	{
		if(opt==0)
			g[st].push_back((node_g){5*n+k,w});
		else
			g[n+k].push_back((node_g){st,w});
		return;
	}
	change(l,r,st,w,opt,k<<1);
	change(l,r,st,w,opt,k<<1|1);
}
void dij(int s)
{
	memset(dis,0x3f,sizeof(dis));
	q.push((node_g){s,0});
	dis[s]=0;
	while(!q.empty())
	{
		node_g u=q.top();
		q.pop();
		if(vis[u.e])
			continue;
		vis[u.e]=1;
		for(int i=0;i<g[u.e].size();i++)
		{
			int v=g[u.e][i].e;
			long long w=g[u.e][i].w;
			if(w+dis[u.e]<dis[v])
			{
				dis[v]=w+dis[u.e];
				q.push((node_g){v,dis[v]});
			}
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m>>s;
	build(1,n,1);
	for(int i=1;i<=m;i++)
	{
		cin>>opt;
		if(opt==1)
		{
			cin>>l>>r>>w;
			if(l==r)
				continue;
			g[l].push_back((node_g){r,w});
		}
		else
		{
			opt-=2;
			cin>>u>>l>>r>>w;
			change(l,r,u,w,opt,1);
		}
	}
	dij(s);
	for(int i=1;i<=n;i++)
	{
		if(dis[i]==dis[0])
			cout<<"-1\n";
		else
			cout<<dis[i]<<'\n';
	}
	return 0;
}