[bzoj5462][loj#2585][线段树]新家

版权声明:蒻蒟的bolg... https://blog.csdn.net/Rose_max/article/details/85253739

Description

五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示。小明是
一位时光旅行者,他知道在这条街上,在过去现在和未来共有 n 个商店出现。第 i 个商店可以使用四个整数 x_i , t_i, a_i,
b_i 描述,它们分别表示:商店的坐标、商店的类型、商店开业的年份、商店关闭的年份。
小明希望通过时光旅行,选择一个合适的时间,住在五福街上的某个地方。他给出了一份他可能选择的列表,上面 包括了 q
个询问,每个询问用二元组(坐标,时间)表示。第 i 对二元组用两个整数 l_i, y_i 描述,分别表示 选择的地点 l_i 和年份 y_i
。 现在,他想计算出在这些时间和地点居住的生活质量。他定义居住的不方便指数为:在居住的年份,离居住点最远 的商店类型到居住点的距离。类型
t 的商店到居住点的距离定义为:在指定的年份,类型 t 的所有营业的商店中 ,到居住点距离最近的一家到居住点的距离。我们说编号为 i
的商店在第 y 年在营业当且仅当 a_i <= y <= b_i 。注意,在某些年份中,可能在五福街上并非所有 k
种类型的商店都有至少一家在营业。在这种情况下,不方便 指数定义为 -1。你的任务是帮助小明求出每对(坐标,时间)二元组居住的不方便指数。

Input

第一行包含三个整数 n , k 和 q,分别表示商店的数量、商店类型的数量和(坐标,时间)二元组的数量。 接下来 n
行,每行包含四个整数 x_i, t_i, a_i, 和 b_i 用于描述一家商店,意义如题面所述 接下来 q 行,每行包含两个整数
l_i, 和 y_i ,表示一组(坐标,时间)查询 (1<= n,q<= 3e5,1<= k <= n) (1<= x_i,a_i,b_i
<= 1e9,1<= t_i <= k,a_i <= b_i) (1<= l_i,y_i <= 1e8)

Output

输出一行,包含q个整数,依次表示对于q组(坐标、时间)询问求出的结果。

Sample Input

4 2 4

3 1 1 10

9 2 2 4

7 2 5 7

4 1 8 10

5 3

5 6

5 9

1 10

Sample Output

4

2

-1

-1

题解

建议前往loj以获得更加阅读体验…
是被tyb所说的线段树分治吸引过来的…然而并不需要好吧…
没有t的限制的话说不定我还是会做的…
单组询问的话很容易想到二分一个答案然后check [ x m , x + m ] [x-m,x+m] 这段范围里面是否包含了所有的颜色,数颜色就好了
虽然这样我似乎只会 n l o g n nlogn 的…
思考一下,我们其实要求的并不是这段区间里有多少种颜色,而仅仅是想知道是否包含所有颜色
不妨动态维护一下每种商店在第 i i 个位置前一个商店的位置 p r e [ i ] pre[i]
每个位置的权赋为在这个位置的商店的 p r e [ i ] pre[i] 的最小值
没有商店就赋为inf
这样的话,对于 ( L , R ) (L,R) 的区间,我们事实上只需要知道 ( R + 1 , + ) (R+1,+\infin) 这一段的最小权值是否小于L
因为最小权值总是在 R R 之后第一个出现的某种商店的 p r e [ i ] pre[i] 产生的
我们可以给每个节点开一个 m u l t i s e t multiset ,维护这个节点所有商店的 p r e [ i ] pre[i]
这样单组询问就可以 l o g 2 log^2
为了避免相同时间相同位置出现同样的商店,我们可以预处理一下…使得每种商店在同一时间同一位置只出现了一个。时间其实可以拆分成两个,一个加入这个商店的时间和一个删除这个商店的时间
全局维护商店种类个set,用于找前驱后继
插入 0 , i n f 0,inf 有助体验
没有卡常…跑的极慢…
主要的思路方式还是通过 p r e [ i ] &gt; i pre[i]-&gt;i 这一段不可能再出现这种颜色来做到的…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(int x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=1000005;

int dcre[4*MAXN],tp;
int n,K,Q;
multiset<int> se1[MAXN];
multiset<int>::iterator it;
struct segtree
{
	multiset<int> se2[4*MAXN];
	int mn[4*MAXN];
	void buildtree(int now,int l,int r)
	{
		if(l==r)
		{
			if(l!=tp+1)mn[now]=999999999;
			else
			{
				for(int i=1;i<=K;i++)se2[now].insert(0);
				mn[now]=0;
			}
			return ;
		}
		int mid=(l+r)/2;
		buildtree(now<<1,l,mid);buildtree(now<<1|1,mid+1,r);
		mn[now]=min(mn[now<<1],mn[now<<1|1]);
	}
	void pushin(int now,int l,int r,int p,int lst)
	{
		if(l==r)
		{
			se2[now].insert(lst);it=se2[now].begin();
			mn[now]=*it;
			return ;
		}
		int mid=(l+r)/2,lc=now<<1,rc=now<<1|1;
		if(p<=mid)pushin(lc,l,mid,p,lst);
		else pushin(rc,mid+1,r,p,lst);
		mn[now]=min(mn[lc],mn[rc]);
	}
	void popout(int now,int l,int r,int p,int de)
	{
		if(l==r)
		{
			it=se2[now].find(de);se2[now].erase(it);
			it=se2[now].begin();mn[now]=*it;
			if(!se2[now].size())mn[now]=999999999;
			return ;
		}
		int mid=(l+r)/2,lc=now<<1,rc=now<<1|1;
		if(p<=mid)popout(lc,l,mid,p,de);
		else popout(rc,mid+1,r,p,de);
		mn[now]=min(mn[lc],mn[rc]);
	}
	int qry(int now,int l,int r,int ql,int qr)
	{
		if(l==ql&&r==qr)return mn[now];
		int mid=(l+r)/2,lc=now<<1,rc=now<<1|1;
		if(qr<=mid)return qry(lc,l,mid,ql,qr);
		else if(mid+1<=ql)return qry(rc,mid+1,r,ql,qr);
		else return min(qry(lc,l,mid,ql,mid),qry(rc,mid+1,r,mid+1,qr));
	}
}seg;

struct event
{
	int op1,op2,pos,t;//操作类型 加入还是删除   位置   时间 
	event(){}
	event(int _op1,int _op2,int _pos,int _t){op1=_op1;op2=_op2;pos=_pos;t=_t;} 
}E[4*MAXN];int len;
bool tcmp(event n1,event n2)
{
	if(n1.t!=n2.t)return n1.t<n2.t;
	return n1.op1>n2.op1;
}
struct shop
{
	int op,l,r,pos;
	shop(){}
	shop(int _op,int _pos,int _l,int _r){op=_op;pos=_pos;l=_l;r=_r;}
}s1[MAXN];
bool cmp(shop n1,shop n2)
{
	if(n1.op!=n2.op)return n1.op<n2.op;
	if(n1.pos!=n2.pos)return n1.pos<n2.pos;
	return n1.l!=n2.l?n1.l<n2.l:n1.r>n2.r;
}

struct ask{int p,t;}w[MAXN];

void md(event tmp)
{
	if(tmp.op2==1)//加入
	{
		int g=tmp.pos;
		it=se1[tmp.op1].lower_bound(g);
		int u2=*it;--it;
		int u1=*it;seg.popout(1,0,tp+1,u2,u1);
		seg.pushin(1,0,tp+1,u2,g);seg.pushin(1,0,tp+1,g,u1);
		se1[tmp.op1].insert(tmp.pos);
	}
	else
	{
		int g=tmp.pos;
		it=se1[tmp.op1].lower_bound(g);
		--it;int u1=*it;
		++it;++it;int u2=*it;
		--it;se1[tmp.op1].erase(it);
		seg.popout(1,0,tp+1,g,u1);seg.popout(1,0,tp+1,u2,g);
		seg.pushin(1,0,tp+1,u2,u1);
	}
}
int fd(int p1,int dis)
{
	int ret;
	if(dis<0)
	{
		int l=1,r=p1;dis=-dis;
		while(l<=r)
		{
			int mid=(l+r)/2;
			if(dcre[p1]-dcre[mid]<=dis)ret=mid,r=mid-1;
			else l=mid+1;
		}
	}
	else
	{
		int l=p1,r=tp;
		while(l<=r)
		{
			int mid=(l+r)/2;
			if(dcre[mid]-dcre[p1]<=dis)ret=mid,l=mid+1;
			else r=mid-1;
		}
	}
	return ret;
}
int answer[MAXN];
void solve(event tmp)
{
	if(seg.qry(1,0,tp+1,tp+1,tp+1)==0){answer[tmp.op2]=-1;return ;}
	int nw=tmp.pos;
	int l=0,r=1e9,re=-1;
	while(l<=r)
	{
		int mid=(l+r)/2;
		int n1=fd(nw,-mid),n2=fd(nw,mid);
		if(seg.qry(1,0,tp+1,n2+1,tp+1)>=n1)re=mid,r=mid-1;
		else l=mid+1;
	}
	answer[tmp.op2]=re;
}
int main()
{
	n=read();K=read();Q=read();
	for(int i=1;i<=n;i++)
	{
		s1[i].pos=dcre[++tp]=read();s1[i].op=read();
		s1[i].l=read();s1[i].r=read()+1;
	}
	for(int i=1;i<=Q;i++)w[i].p=dcre[++tp]=read(),w[i].t=read();
	sort(dcre+1,dcre+1+tp);
	tp=unique(dcre+1,dcre+1+tp)-(dcre+1);
	for(int i=1;i<=n;i++)s1[i].pos=lower_bound(dcre+1,dcre+tp+1,s1[i].pos)-(dcre);
	for(int i=1;i<=Q;i++)w[i].p=lower_bound(dcre+1,dcre+tp+1,w[i].p)-(dcre);
	
	sort(s1+1,s1+1+n,cmp);
	int ggg,ln=0;
	for(int i=1;i<=n;i=ggg+1)
	{
		ggg=i;int r=s1[i].r;
		while(ggg<n&&s1[ggg+1].op==s1[i].op&&s1[ggg+1].pos==s1[ggg].pos&&s1[ggg+1].l<=r)r=max(s1[++ggg].r,r);
		s1[++ln]=shop(s1[ggg].op,s1[ggg].pos,s1[i].l,r);
	}
	for(int i=1;i<=K;i++)se1[i].insert(0),se1[i].insert(tp+1);
	dcre[tp+1]=dcre[tp]+1;
	//-1表示询问   其他表示商店类型 
	for(int i=1;i<=ln;i++)
	{
		E[++len]=event(s1[i].op,1,s1[i].pos,s1[i].l);
		E[++len]=event(s1[i].op,-1,s1[i].pos,s1[i].r);
	}
	for(int i=1;i<=Q;i++)E[++len]=event(-1,i,w[i].p,w[i].t);
	sort(E+1,E+1+len,tcmp);
	
	seg.buildtree(1,0,tp+1);
	for(int i=1;i<=len;i++)
	{
		if(E[i].op1>0)md(E[i]);
		else solve(E[i]);
	}
	for(int i=1;i<=Q;i++)pr2(answer[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/85253739