「NOI2019」弹跳

「NOI2019」弹跳

Part 32

暴力建图跑 floyd。

Part 52

map 离散化,然后跑 dij。

Part 72

此时只有一维,那么相当于是一个点向一个区间连边,容易想到线段树优化建图。

但其实这里并不用把图建出来,我们直接用线段树维护未被遍历过且 \(dis\) 最小的城市,然后遍历他的边做一个区间取 \(\min\) 即可。

复杂度 \(O(n\log n)\)

Part 88

同 Part 77 的做法,不过此时问题变成二维,那么我们直接上个树套树即可。

时空均为 \(O(n \log^2n)\)。但是内存太大了,所以满不了。

期望得分 88。

部分分代码在正解下面。

Part 100

线段树套线段树内存压不下去。只能换写法。

这题直接跑 dij 的瓶颈就在于边太多了,而有些边根本不会更新答案,就导致每个点被遍历的次数是 \(O(m)\) 的。如果能让每个点遍历的次数降为 \(O(1)\) 的就能解决问题。

这类题有一个套路就是将边也看做一类点。

我们发现边是矩阵,发现这个矩阵内所有点区间取 \(\min\) 的值是一样的。

所以我们可以将边看做点,定义其 \(dis\) 值为这条矩阵起点的 \(dis\) 加上边的权值。

那么我们每次取出一个 \(dis\) 最小的矩阵,不难发现这个矩阵内的所有点的 \(dis\) 值肯定再之后不会变的更优了(想想 dij 的过程)。

这样我们就保证了一个点只会被遍历一遍。

我们将所有在这个矩阵内的还会被松弛的点松弛,并且用这个点去更新以该点为起点的边即可。

那么问题变成了如何找到一个矩阵内的所有未被松弛的点。

先考虑如何找到一个矩阵内所有点。可以用线段树套 set。空间是 \(O(n\log n)\) 的。

set 支持删除操作,所以一个点如果被松弛了我们直接将他删除。那么就可以快速找到一个矩阵内所有未被松弛的点。

时间复杂度是 \(O(n\log^2n)\)

代码如下:

#include<bits/stdc++.h>
#define ls(k) (k<<1)
#define rs(k) (k<<1|1)
using namespace std;
const int MAXN = 7e4+4;
const int INF = 1e9;
int n,m,w,h,X[MAXN],Y[MAXN],dis[MAXN];
struct E
{
	int L,R,D,U,t;
};
struct node
{
	int L,R,D,U,dis;
	bool operator < (const node &x)const
	{
		return dis>x.dis;
	}
};
struct city
{
	int Y,id;
	bool operator < (const city &x)const
	{
		return Y!=x.Y?Y<x.Y:id<x.id;
	}
};
vector <E> e[MAXN];
multiset<city> S[MAXN<<2];
priority_queue<node> q;
bool vis[MAXN];
void Add(int p,int k,int l,int r,int id)
{
	S[k].insert(city{Y[id],id});
	if(l==r) return ;
	int mid=l+r>>1;
	if(p<=mid) Add(p,ls(k),l,mid,id);
	else Add(p,rs(k),mid+1,r,id);
}
void upd(int le,int ri,int k,int l,int r,int D,int U,int d)
{
	if(le<=l&&r<=ri)
	{
		multiset<city>::iterator it=S[k].lower_bound(city{D,0});
		while(it!=S[k].end()&&it->Y<=U)
		{
			if(!vis[it->id])
			{
				vis[it->id]=1;dis[it->id]=d;
				for(E v:e[it->id])
					q.push(node{v.L,v.R,v.D,v.U,v.t+d});
			}
			multiset<city>::iterator it1=it;
			++it;S[k].erase(it1);
		}
		return ;
	}
	int mid=l+r>>1;
	if(le<=mid) upd(le,ri,ls(k),l,mid,D,U,d);
	if(ri>mid)  upd(le,ri,rs(k),mid+1,r,D,U,d);
}
void Solve()
{
	memset(dis,0x3f,sizeof dis);
	q.push(node{X[1],X[1],Y[1],Y[1],0});
	while(!q.empty())
	{
		node p=q.top();q.pop();
		upd(p.L,p.R,1,1,n,p.D,p.U,p.dis);
	}
}
int main()
{
	freopen("jump.in","r",stdin);
	freopen("jump.out","w",stdout);
	scanf("%d %d %d %d",&n,&m,&w,&h);
	for(int i=1;i<=n;++i) scanf("%d %d",&X[i],&Y[i]);
	for(int i=1;i<=n;++i) Add(X[i],1,1,n,i);
	bool flag=1;
	for(int i=1;i<=m;++i)
	{
		int p,t,L,R,D,U;
		scanf("%d %d %d %d %d %d",&p,&t,&L,&R,&D,&U);
		e[p].push_back(E{L,R,D,U,t});
	}
	Solve();
	for(int i=2;i<=n;++i) printf("%d\n",dis[i]);
	return 0;
}

部分分代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 7e4+4;
const int INF = 1e9;
int n,m,w,h,X[MAXN],Y[MAXN];
struct E
{
	int L,R,D,U,t;
};
vector <E> e[MAXN];
namespace pt32
{
	int f[105][105];
	void Solve()
	{
		memset(f,0x3f,sizeof f);
		for(int i=1;i<=n;++i) f[i][i]=0;
		for(int i=1;i<=n;++i)
		{
			for(E v:e[i])
			{
				int L=v.L,R=v.R,D=v.D,U=v.U,t=v.t;
				for(int j=1;j<=n;++j)
				{
					if(L<=X[j]&&X[j]<=R&&D<=Y[j]&&Y[j]<=U)
						f[i][j]=min(f[i][j],t);
				}
			}
		}
		for(int k=1;k<=n;++k) for(int i=1;i<=n;++i) for(int j=1;j<=n;++j)
			f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
		for(int i=2;i<=n;++i) printf("%d\n",f[1][i]);
	}
}
namespace pt52
{
	struct Ed
	{
		int to,w;
	};
	vector <Ed> g[MAXN];
	map<pair<int,int>,int> mp;
	void link(int u,int v,int w){g[u].push_back(Ed{v,w});}
	int dis[MAXN];bool vis[MAXN];
	struct node
	{
		int p,dis;
		bool operator < (const node&x)const
		{
			return dis>x.dis;
		}
	};
	void dij()
	{
		priority_queue <node> q;
		for(int i=1;i<=n;++i) dis[i]=INF;
		dis[1]=0;q.push(node{1,0});
		while(!q.empty())
		{
			node cur=q.top();
			q.pop();
			int p=cur.p;
			if(vis[p]) continue;
			vis[p]=1;
			for(Ed v:g[p])
			{
				int to=v.to,w=v.w;
				if(dis[to]>dis[p]+w)
				{
					dis[to]=dis[p]+w;
					q.push(node{to,dis[to]});
				}
			}
		}
	}
	void Solve()
	{
		for(int i=1;i<=n;++i) mp[make_pair(X[i],Y[i])]=i;
		for(int i=1;i<=n;++i)
		{
			for(E v:e[i])
			{
				pair <int,int> to=make_pair(v.L,v.D);
				if(mp.count(to)) link(i,mp[to],v.t);
			}
		}
		dij();
		for(int i=2;i<=n;++i) printf("%d\n",dis[i]);
	}
}
namespace pt72
{

	const int MAXT = 5e4+5;
	int pos[MAXN];
	struct Tree
	{
		#define ls(k) (k<<1)
		#define rs(k) (k<<1|1)	
		int tg[MAXT<<2],mx[MAXT<<2],id[MAXT<<2];
		void pu(int k)
		{
			if(!id[ls(k)]||!id[rs(k)])
			{
				id[k]=id[ls(k)]|id[rs(k)];
				mx[k]=id[ls(k)]?mx[ls(k)]:mx[rs(k)];
				return ;
			}
			if(mx[ls(k)]<=mx[rs(k)]) id[k]=id[ls(k)];
			else id[k]=id[rs(k)];
			mx[k]=min(mx[ls(k)],mx[rs(k)]);
		}
		void build(int k,int l,int r)
		{
			tg[k]=INF;
			if(l==r)
			{
				if(l==X[1]) mx[k]=0;
				else mx[k]=INF;
				id[k]=l;
				return ;
			}
			int mid=l+r>>1;
			build(ls(k),l,mid);
			build(rs(k),mid+1,r);
			pu(k);
		}
		void pd(int k)
		{
			mx[ls(k)]=min(mx[ls(k)],tg[k]);mx[rs(k)]=min(mx[rs(k)],tg[k]);
			tg[ls(k)]=min(tg[ls(k)],tg[k]);tg[rs(k)]=min(tg[rs(k)],tg[k]);
		}
		void clear(int p,int k,int l,int r)
		{
			if(l==r) {id[k]=0;return ;}
			int mid=l+r>>1;pd(k);
			if(p<=mid) clear(p,ls(k),l,mid);
			else clear(p,rs(k),mid+1,r);
			pu(k);
		}
		void upd(int le,int ri,int k,int l,int r,int x)
		{
			if(le<=l&&r<=ri)
			{
				tg[k]=min(tg[k],x);
				mx[k]=min(mx[k],x);
				return ;
			}
			int mid=l+r>>1;pd(k);
			if(le<=mid) upd(le,ri,ls(k),l,mid,x);
			if(ri>mid)  upd(le,ri,rs(k),mid+1,r,x);
			pu(k);
		}
		int Q(int p,int k,int l,int r)
		{
			if(l==r) return mx[k];
			int mid=l+r>>1;pd(k);
			if(p<=mid) return Q(p,ls(k),l,mid);
			else return Q(p,rs(k),mid+1,r);
		}
	}T;
	void Solve()
	{
		for(int i=1;i<=n;++i) pos[X[i]]=i;
		T.build(1,1,n);
		while(T.id[1]!=0)
		{
			int p=T.id[1];
			p=pos[p];
			for(E v:e[p])
			{
				int t=v.t,L=v.L,R=v.R,disp=T.mx[1];	
				T.upd(L,R,1,1,n,disp+t);
			}
			T.clear(T.id[1],1,1,n);
		}
		for(int i=2;i<=n;++i)
			printf("%d\n",T.Q(X[i],1,1,n));
	}
}
int main()
{
//	cout<<1.0*(&Small-&Sunny)/1024/1024<<"MB"<<endl;
	
//	freopen("jump.in","r",stdin);
//	freopen("jump.out","w",stdout);
	scanf("%d %d %d %d",&n,&m,&w,&h);
	for(int i=1;i<=n;++i) scanf("%d %d",&X[i],&Y[i]);
	bool flag=1;
	for(int i=1;i<=m;++i)
	{
		int p,t,L,R,D,U;
		scanf("%d %d %d %d %d %d",&p,&t,&L,&R,&D,&U);
		e[p].push_back(E{L,R,D,U,t});
		flag&=(L==R)&&(D==U);
	}
	
	if(n<=100) pt32::Solve();
	else if(h==1) pt72::Solve();
	else if(flag) pt52::Solve();
	
//	else if(n<=25000) pt88::Solve();

//	pt72::Solve();
	return 0;
}
posted @ 2022-04-26 16:05  夜空之星  阅读(40)  评论(0编辑  收藏  举报