您的位置:首页 > 其它

[BZOJ2716][Violet 3]天使玩偶(cdq分治+bit)

2017-01-08 17:40 399 查看

题目描述

传送门

题解

上下左右想想就不好搞啊…所以我们每一次只统计某个点左下方与它最近的,然后做4遍

|x-x’|+|y-y’|=(x+y)-(x’+y’),也就是求x+y最大的点

然后这不就和三维偏序问题差不多了么?

按照时间排序分治,每一次对(l,mid)和(mid+1,r)按照x排序,然后两个指针,对于每一个询问将横坐标都小于等于它的点按照y加入bit,权值为x+y,查询最大值

然而写完了之后狂T不止啊…这一波常数卡得

首先归并排序的方法确实要快很多

然后就是学了一点hxy的姿势:只有询问才加点,不是询问就不加,也就是能不做的就不做

sort慢

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
using namespace std;
#define N 1000005

int n,m,opt,acnt,bcnt,pa,pb,tot,inf,INF;
int ans
,ch
;
struct hp{int x,y,id;bool flag;}p
,q
;
int C
;

int read()
{
int x=0;char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
void add(int loc,int val)
{
if (!loc) return;
for (int i=loc;i<=inf;i+=i&(-i))
C[i]=max(C[i],val);
}
void cover(int loc)
{
if (!loc) return;
for (int i=loc;i<=inf;i+=i&(-i))
C[i]=-1;
}
int query(int loc)
{
int ans=-1;
for (int i=loc;i>=1;i-=i&(-i))
ans=max(ans,C[i]);
return ans;
}
void cdq(int l,int r)
{
if (l>=r) return;
int mid=(l+r)>>1;
pa=l,pb=mid+1;
for (int i=l;i<=r;++i)
if (p[i].id<=mid) q[pa++]=p[i];
else q[pb++]=p[i];
for (int i=l;i<=r;++i) p[i]=q[i];
pa=l,pb=mid+1;tot=0;
while (pb<=r)
{
if (p[pb].flag)
{
while (pa<=mid&&p[pa].x<=p[pb].x)
{
if(!p[pa].flag)add(p[pa].y,p[pa].x+p[pa].y);
ch[++tot]=p[pa].y;
++pa;
}
int t=query(p[pb].y);
if(t!=-1)ans[p[pb].id]=min(ans[p[pb].id],p[pb].x+p[pb].y-t);
}
++pb;
}
for (int i=1;i<=tot;++i)cover(ch[i]);
cdq(l,mid);
cdq(mid+1,r);
}
int cmp(hp a,hp b){return a.x<b.x;}
int main()
{
n=read();m=read();
for (int i=1;i<=n;++i)
{
p[i].x=read();p[i].y=read();
p[i].id=i;
inf=max(inf,p[i].x);inf=max(inf,p[i].y);
}
m+=n;
for (int i=n+1;i<=m;++i)
{
opt=read();
if(opt==2)p[i].flag=1;
p[i].x=read();p[i].y=read();
p[i].id=i;
inf=max(inf,p[i].x);inf=max(inf,p[i].y);
}
memset(ans,127,sizeof(ans));INF=ans[0];
memset(C,-1,sizeof(C));
sort(p+1,p+m+1,cmp);cdq(1,m);
for (int i=1;i<=m;++i)p[i].y=inf-p[i].y+1;sort(p+1,p+m+1,cmp);cdq(1,m);
for (int i=1;i<=m;++i)p[i].x=inf-p[i].x+1;sort(p+1,p+m+1,cmp);cdq(1,m);
for (int i=1;i<=m;++i)p[i].y=inf-p[i].y+1;sort(p+1,p+m+1,cmp);cdq(1,m);
for (int i=n+1;i<=m;++i)
if (ans[i]!=INF) printf("%d\n",ans[i]);
}


总结

①卡常数技巧:能不做的就不做。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: