orz zzk sunboy
因为蛇是水平或竖直的,不可能同时挡住水平面上的箭和竖直面上的箭。
所以我们可以把二维平面上的问题变成一维线段覆盖问题。
线段覆盖问题我们有贪心的策略:假设目前最远覆盖到 now ,那么所有能够接下去覆盖的线段 {[L,R]|L≤now+1} 中,我们肯定选右端点最大的,这个很显然。不停选择右端点最大的线段更新 now ,最后就可以得到最优解了。
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<cstring>
using namespace std;
#define min(a,b) (a)<(b)?(a):(b)
#define maxx(a,b) (a)>(b)?(a):(b)
int m,n,k,t,x1,x2,y1,y2;
struct node{
int a1,a2,b;
}line[100005],row[100005];
bool cmp(node n1,node n2){
return n1.a1<n2.a1;
}
int dp[100005];
int main(){
scanf("%d",&t);
register int i,j;
for (int o=0;o<t;o++)
{
scanf("%d %d %d",&n,&k,&m);
int min=(n-k)/2+1;
int max = (n+k)/2;
int ltt=0,rtt=0;
for (i=0;i<m;i++)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
if (x1==x2)
{
node tmp;
tmp.b=x2;
tmp.a1=min(y1,y2);
tmp.a2=maxx(y1,y2);
if (tmp.a2<min||tmp.a1>max)
{
if (tmp.b>=min&&tmp.b<=max)
{
tmp.a1=tmp.a2=tmp.b;
row[rtt]=tmp;
rtt++;
}
}
else
{
line[ltt]=tmp;
ltt++;
}
}
if (y1==y2)
{
node tmp;
tmp.b=y1;
tmp.a1=min(x1,x2);
tmp.a2=maxx(x1,x2);
if (tmp.a2<min||tmp.a1>max)
{
if (tmp.b>=min&&tmp.b<=max)
{
tmp.a1=tmp.a2=tmp.b;
line[ltt]=tmp;
ltt++;
}
}
else
{
row[rtt]=tmp;
rtt++;
}
}
}
sort(line+0,line+ltt,cmp);
sort(row+0,row+rtt,cmp);
memset(dp,0,sizeof(dp));
dp[0]=min-1;
int index=0;
int lineans=-1;
bool flag=false;
for (i=0;i<=m;i++)
{
dp[i+1]=dp[i];
while (1)
{
if (index<ltt&&line[index].a1<=dp[i]+1)
{
if (line[index].a2>=max)
{
lineans=i+1;
flag=true;
break;
}
dp[i+1]=maxx(dp[i+1],line[index].a2);
index++;
}else break;
}
if (flag) break;
}
if (!flag)
{
printf("-1\n");
continue;
}
flag=false;
memset(dp,0,sizeof(dp));
index=0;
int rowans=-1;
dp[0]=min-1;
for (i=0;i<=m;i++)
{
dp[i+1]=dp[i];
while (1)
{
if(index<rtt&&row[index].a1<=dp[i]+1)
{
if (row[index].a2>=max)
{
rowans=i+1;
flag=true;
break;
}
dp[i+1]=maxx(dp[i+1],row[index].a2);
index++;
}
else break;
}
if (flag) break;
}
if (!flag)
{
printf("-1\n");
continue;
}
printf("%d\n",lineans+rowans);
}
}