Description
二维坐标平面内有n个圆,第i个圆圆心在(Xi,Yi),半径为Ri,权值Vi。任何两个圆都不会相交(也不会相切),但是圆与圆之间可能存在包含关系。当我们在一个圆里面的时候,我们必须经过它的边界一次,才能走出这个圆。
对于不同的两个圆A、B,如果可以从A到B且经过不超过K次边界,则称A、B是连通的。现在的问题是:对于所有的连通的一对圆(A,B),权值差的绝对值最大有多少。即找到max{ |VA – VB|, 其中A B连通}。
对于100%的数据,T ≤ 10, 2 ≤ n ≤ 50000, 2 ≤ K ≤ 100, 0 < Ri ≤ 200000000, -1000000000 ≤ Xi, Yi, Vi ≤ 1000000000
Solution
首先我们把每个圆看做一个点,将包含这个圆的最小圆看做它的父亲,这样构成一棵树,接下来就是树上距离不超过K的点对权值差的最大值,随便DP一下即可。
我们考虑如何求包含某个圆的最小圆。
用扫描线从左到右扫,用一个set维护每个圆与扫描线的交点之间的位置关系。
由于圆与圆之间不会相交,也就意味着交点 之间的相对顺序是不会改变的。
我们在加入一个圆的两个交点时,考虑比上交点高的第一个点。
如果这个点是一个上交点,那么新加的圆的父亲就是那一个点对应的圆。
否则新加的圆的父亲与那一个点对应的圆的父亲相同。
做到一个圆的最右端时就将两个交点删除。
这样就在
O
(
T
(
n
log
n
+
n
k
)
)
O(T(n\log n+nk))
O(T(nlogn+nk))的复杂度做完了。
显然后面nk的部分可以优化,大可以采用点分治/长链剖分等做法。
毒瘤的是原题卡空间
Code
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 100005
#define LL long long
using namespace std;
priority_queue<int,vector<int>,greater<int> > hp;
int t,fs[N],nt[N],dt[N],a[N][4],now,fa[N],m1,n,m,mx[20005][101],mi[20005][101],ans,rt[N],n1,mx1;
struct node
{
int w,x,p;
}d[N];
bool cmp(node x,node y)
{
return x.x<y.x;
}
LL sqr(LL x)
{
return x*x;
}
struct nd
{
int w,p;
friend double wz(nd x)
{
if(!x.p) return a[x.w][1]-sqrt(sqr(a[x.w][2])-sqr(a[x.w][0]-now));
else return a[x.w][1]+sqrt((sqr(a[x.w][2])-sqr(a[x.w][0]-now)));
}
friend bool operator<(nd x,nd y)
{
return (wz(x)<wz(y));
}
};
set<nd> h;
void link(int x,int y)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
}
void dfs(int k,int fa)
{
rt[k]=0;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=fa)
{
dfs(p,k);
if(!rt[k])
{
rt[k]=rt[p];
fod(j,m,1)
{
mx[rt[k]][j]=mx[rt[k]][j-1],mi[rt[k]][j]=mi[rt[k]][j-1];
if(k) mx[rt[k]][j]=max(mx[rt[k]][j],a[k][3]),mi[rt[k]][j]=min(mi[rt[k]][j],a[k][3]);
ans=max(ans,mx[rt[k]][j]-mi[rt[k]][j]);
}
if(k) mx[rt[k]][0]=mi[rt[k]][0]=a[k][3];
else mx[rt[k]][0]=-1e9,mi[rt[k]][0]=1e9;
}
else
{
fo(j,0,m)
{
if(j!=m) ans=max(ans,max(mx[rt[k]][j]-mi[rt[p]][m-j-1],mx[rt[p]][m-j-1]-mi[rt[k]][j]));
if(j) mx[rt[k]][j]=max(mx[rt[k]][j],mx[rt[p]][j-1]),mi[rt[k]][j]=min(mi[rt[k]][j],mi[rt[p]][j-1]);
}
hp.push(rt[p]);
}
}
}
if(!rt[k])
{
rt[k]=hp.top(),hp.pop();
fo(j,0,m) mx[rt[k]][j]=mi[rt[k]][j]=a[k][3];
}
}
int main()
{
cin>>t;
int cnt=0;
while(t--)
{
int l=0;
m1=0;
while(!hp.empty()) hp.pop();
memset(fs,0,sizeof(fs));
scanf("%d%d",&n,&m);
fo(i,1,n) hp.push(i);
a[0][0]=a[0][1]=0,a[0][2]=2e9;
fo(i,1,n)
{
scanf("%d%d%d%d",&a[i][0],&a[i][1],&a[i][2],&a[i][3]);
d[++l]=(node){i,a[i][0]-a[i][2],0},d[++l]=(node){i,a[i][0]+a[i][2],1};
}
sort(d+1,d+l+1,cmp);
h.clear();
h.insert((nd){0,0}),h.insert((nd){0,1});
ans=0;
fo(i,1,l)
{
now=d[i].x;
if(!d[i].p)
{
set<nd>::iterator it=h.upper_bound((nd){d[i].w,1});
nd p1=*it;
if(p1.p==0) fa[d[i].w]=fa[p1.w];
else fa[d[i].w]=(*it).w;
link(fa[d[i].w],d[i].w);
now=d[i].x+1;
h.insert((nd){d[i].w,0}),h.insert((nd){d[i].w,1});
now=d[i].x;
}
else h.erase((nd){d[i].w,0}),h.erase((nd){d[i].w,1});
}
dfs(0,0);
cnt++;
printf("Case %d: %d\n",cnt,ans);
}
}