APIO2018 新家

190 篇文章 2 订阅
21 篇文章 0 订阅

题面

题意

在一条路上有n家商店,每个商店有一个类型,在某段时间内在某个位置上存在,每次询问给出一个时间和一个地点,求该时间从该地点出发最少走多少路才可以到达任意一种类型的商店。

做法

首先可以离线处理,根据时间进行排序,那么没家商店就都可以看作是在某个时间加入,再从某个时间删除,并询问某个点到所有类型点的最小距离的最大值。
这个可以进行二分,这样问题就转化为了,询问此时某一段区间内是否存在所有类型的商店。
对于这个问题,我们可以对于每一个商店记录它左边的第一个同类型的商店的位置pre,那么如果商店 i i i p r e pre pre j j j,就说明区间 [ i + 1 , j − 1 ] [i+1,j-1] [i+1,j1]中不存在与它同类型的商店,据此,如果所有大于 r r r的商店的 p r e pre pre均大于等于 l l l,则说明区间 [ l , r ] [l,r] [l,r]中包含所有类型的商店(用线段树维护即可),除非某种类型的商店不存在于 l l l及其右边,对于这种情况只要记录一下每种类型的商店最右边的位置即可。
这题最麻烦的地方在于一个位置可以有多个商店(类型可以相同),因此处理时,可以用multiset记录每种类型的商店的所有商店位置(维护每个商店的pre),然后对于每个位置用一个支持删除的优先队列来维护该位置上所有商店的pre的最小值,再用一个线段树来维护这些优先队列的top即可。

代码

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 300100
using namespace std;

int n,m,Q,bb,cc,tb,tc,ss,tt,ans[N],b[N],cnt[N],cl;
void chg(int now,int l,int r,int u,int v);
struct Shop
{
    int cz,pos,type,ti;
    bool operator < (const Shop &u) const
    {
	if(ti!=u.ti) return ti<u.ti;
	return cz<u.cz;
    }
}shop[N*3];
struct Pq
{
    int tp,id;
    priority_queue<int,vector<int>,greater<int> >a,b;
    void cle(){for(;!b.empty() && a.top()==b.top();a.pop(),b.pop());}
    int top(){cle();return a.top();}
    void cg(){if(tp!=top()) tp=top(),chg(1,1,bb,id,tp);}
    void push(int u){a.push(u);if(id) cg();}
    void del(int u){b.push(u);if(id) cg();}
}pq[N],ri;
struct Node
{
    int ls,rs,mn;
}node[N<<1];
map<int,int>mb;
multiset<int>se[N];
multiset<int>::iterator it,i2;

inline void add(int u,int v)
{
    if(!cnt[v]) cl--;cnt[v]++;
    se[v].insert(u);
    i2=it=se[v].lower_bound(u);
    it++,i2--;
    pq[u].push(*i2);
    if(it!=se[v].end()) pq[*it].del(*i2),pq[*it].push(u);
    else ri.del(*i2),ri.push(u);
}

inline void del(int u,int v)
{
    cnt[v]--;if(!cnt[v]) cl++;
    i2=it=se[v].lower_bound(u);
    it++,i2--;
    pq[u].del(*i2);
    if(it!=se[v].end()) pq[*it].del(u),pq[*it].push(*i2);
    else ri.del(u),ri.push(*i2);
    se[v].erase(--it);
}

inline void up(int now){int L=node[now].ls,R=node[now].rs;node[now].mn=min(node[L].mn,node[R].mn);}
void build(int now,int l,int r)
{
    if(l==r)
    {
	node[now].mn=INF;
	return;
    }
    int mid=((l+r)>>1);
    node[now].ls=++tt;
    build(tt,l,mid);
    node[now].rs=++tt;
    build(tt,mid+1,r);
    up(now);
}

void chg(int now,int l,int r,int u,int v)
{
    if(l==r)
    {
	node[now].mn=v;
	return;
    }
    int mid=((l+r)>>1);
    if(u<=mid) chg(node[now].ls,l,mid,u,v);
    else chg(node[now].rs,mid+1,r,u,v);
    up(now);
}

int ask(int now,int l,int r,int u,int v)
{
    if(u<=l&&r<=v) return node[now].mn;
    int mid=((l+r)>>1);
    if(v<=mid) return ask(node[now].ls,l,mid,u,v);
    if(u>mid) return ask(node[now].rs,mid+1,r,u,v);
    return min(ask(node[now].ls,l,mid,u,v),ask(node[now].rs,mid+1,r,u,v));
}

inline bool judge(int u,int v)
{
    u=lower_bound(b+1,b+bb+1,u)-b;
    v=upper_bound(b+1,b+bb+1,v)-b-1;
    if(v<u) return 0;
    if(v<bb && ask(1,1,bb,v+1,bb)<u) return 0;
    if(ri.top()<u) return 0;
    return 1;
}

inline int calc(int u)
{
    if(cl) return -1;
    int l,r,mid;
    for(l=0,r=1e8;l<r;)
    {
	mid=((l+r)>>1);
	if(judge(u-mid,u+mid)) r=mid;
	else l=mid+1;
    }
    return l;
}

int main()
{
    int i,j,p,q,o,z;
    cin>>n>>m>>Q;cl=m;
    for(i=1;i<=m;i++) se[i].insert(0),ri.push(0);
    for(i=1;i<=n;i++)
    {
	scanf("%d%d%d%d",&z,&o,&p,&q);
	b[++tb]=z;
	shop[++ss].cz=1;
	shop[ss].pos=z;
	shop[ss].type=o;
	shop[ss].ti=p;
	shop[++ss].cz=3;
	shop[ss].pos=z;
	shop[ss].type=o;
	shop[ss].ti=q;
    }
    for(i=1;i<=Q;i++)
    {
	scanf("%d%d",&p,&q);
	shop[++ss].cz=2;
	shop[ss].pos=p;
	shop[ss].ti=q;
	shop[ss].type=i;
    }
    sort(b+1,b+tb+1);
    for(i=1;i<=tb;i++)
    {
	if(i==1 || b[i]!=b[i-1])
	{
	    b[++bb]=b[i];
	    mb[b[i]]=bb;
	}
    }
    for(i=1;i<=ss;i++) if(shop[i].cz!=2) shop[i].pos=mb[shop[i].pos];

    for(i=1;i<=bb;i++) pq[i].id=i,pq[i].push(INF);
    build(tt=1,1,bb);
    sort(shop+1,shop+ss+1);
    for(i=1;i<=ss;i=j)
    {
	z=shop[j=i].ti;
	for(;j<=ss&&shop[j].ti==z&&shop[j].cz==1;j++)
	    add(shop[j].pos,shop[j].type);
	for(;j<=ss&&shop[j].ti==z&&shop[j].cz==2;j++)
	    ans[shop[j].type]=calc(shop[j].pos);
	for(;j<=ss&&shop[j].ti==z&&shop[j].cz==3;j++)
	    del(shop[j].pos,shop[j].type);
    }
    for(i=1;i<=Q;i++) printf("%d\n",ans[i]);
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值