hsfzLZH1
2019-07-18 19:57:55
给出二维平面上的
暴力连边,边数最多为
暴力分还挺多
观察到每次连边操作只会连接两个结点,暴力连边,边数为
什么,还有其他最短路算法?
开题一看,这不是 线段树优化建图 的题吗?
线段树优化建图,是图论问题中的经典技巧。将所有点按照
(图片来源: NaCly_Fish )
我们对排序后的序列建一棵线段树,线段树上的每个结点向其左右儿子连一条边权为
总点数为
线段树优化建图的经典题目:
CF786B Legacy
P5025 [SNOI2017]炸弹
现在连边从原来的一维变成二维的了。
在做这题时,我考虑了分块套分块,分块套线段树,线段树套线段树等多种方法,最后发现线段树套动态开点线段树比较优秀。
外层
连边时,先找到
然而,这种写法的内存使用超过了限制。一般的实现可以得到
树套树内层使用 set
容器;
不直接连边 。回顾 Dij 的算法流程,有如下写法:用线段树套 set
维护一个矩阵中存在的整点,开始时扩展 set
上删除这些结点。由于每个结点只会被删除和扩展一次,所以这样做的时间复杂度是
同时使用两种优化,时间复杂度是
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
using namespace std;
const int maxn=150010;
int n,m,W,H;
struct city{int id,x,y;bool operator<(city a)const{return y==a.y?id<a.id:y<a.y;};}s[maxn];
set<city>st[maxn*2];
#define lc (o<<1)
#define rc (o<<1|1)
void update(int o,int l,int r,int v)
{
st[o].insert(s[v]);
if(l==r)return;
int mid=(l+r)>>1;
if(s[v].x<=mid)update(lc,l,mid,v);
else update(rc,mid+1,r,v);
}
void deleet(int o,int l,int r,int v)
{
st[o].erase(s[v]);
if(l==r)return;
int mid=(l+r)>>1;
if(s[v].x<=mid)deleet(lc,l,mid,v);
else deleet(rc,mid+1,r,v);
}
struct jumpy{int p,t,l,r,d,u;}e[maxn];
vector<int>g[maxn];
struct node{int x,v;bool operator<(node a)const{return v>a.v;};}x;
priority_queue<node>q;
queue<int>tag;
int dist[maxn];
bool tf[maxn];
void erasse(int o,int l,int r,int id,int v)
{
int ql=e[id].l,qr=e[id].r;
if(r<ql||l>qr)return;
if(ql<=l&&r<=qr)
{
set<city>::iterator lb=lower_bound(st[o].begin(),st[o].end(),(city){0,n+1,e[id].d});
for(;lb!=st[o].end()&&(lb->y)<=e[id].u;lb++)
{
dist[lb->id]=v;tag.push(lb->id);
for(vector<int>::iterator it=g[lb->id].begin();it!=g[lb->id].end();it++)q.push({*it,v+e[*it].t});
}
while(!tag.empty())deleet(1,1,n,tag.front()),tag.pop();
return;
}
int mid=(l+r)>>1;
erasse(lc,l,mid,id,v);erasse(rc,mid+1,r,id,v);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&W,&H);
for(int i=1;i<=n;i++)scanf("%d%d",&s[i].x,&s[i].y),s[i].id=i,update(1,1,n,i);
for(int i=1;i<=m;i++)scanf("%d%d%d%d%d%d",&e[i].p,&e[i].t,&e[i].l,&e[i].r,&e[i].d,&e[i].u),g[e[i].p].push_back(i);
e[0].l=e[0].r=s[1].x;e[0].d=e[0].u=s[1].y;
q.push({0,0});
while(!q.empty())
{
x=q.top();q.pop();
if(tf[x.x])continue;
tf[x.x]=true;
erasse(1,1,n,x.x,x.v);
//for(vector<int>::iterator it=g[x.x].begin();it!=g[x.x].end();it++)q.push({e[*it].p,x.v+e[*it].t});
}
for(int i=2;i<=n;i++)printf("%d\n",dist[i]);
return 0;
}