https://codeforces.com/contest/1472/problem/F
首先我们吧colum离散化,然后对于相邻两个c,他们之间的2*2的矩阵都是可以删除的,对最后的安排结果不会造成影响,那么其实坐标就让他要么差1要么差2
然后再最左边的c的左边和最右边的c的右边一定都是竖着放满的,如果影响到中间是肯定有问题的
最后就从左到右状压dp扫过去就行了,0表示2个都不用向右,1表示上面的放一个横的,要拓展到右边,2表示下面的,3表示上下都向右拓展
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,k,cnt,tot,cas,ans;
struct node
{
int r,c;
}a[maxl];
int b[maxl];
int mp[maxl][3],dp[maxl*2][4];
bool vis[maxl];
char s[maxl];
inline bool cmp(const node &a,const node &b)
{
return a.c<b.c;
}
inline void prework()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].r,&a[i].c);
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
if(a[i].c==a[i-1].c)
b[i]=b[i-1];
else if((a[i].c-a[i-1].c)&1)
b[i]=b[i-1]+1;
else
b[i]=b[i-1]+2;
for(int i=0;i<=b[n];i++)
{
mp[i][1]=mp[i][2]=0;
for(int j=0;j<4;j++)
dp[i][j]=0;
}
for(int i=1;i<=n;i++)
mp[b[i]][a[i].r]=1;
dp[0][0]=1;
for(int i=1;i<=b[n];i++)
if(mp[i][1]==0 && mp[i][2]==0)
{
dp[i][0]|=dp[i-1][0];
dp[i][0]|=dp[i-1][3];
dp[i][2]|=dp[i-1][1];
dp[i][1]|=dp[i-1][2];
dp[i][3]|=dp[i-1][0];
}
else if(mp[i][1]==0)
{
dp[i][0]|=dp[i-1][1];
dp[i][1]|=dp[i-1][0];
}
else if(mp[i][2]==0)
{
dp[i][0]|=dp[i-1][2];
dp[i][2]|=dp[i-1][0];
}else
dp[i][0]=dp[i-1][0];
}
inline void mainwork()
{
}
inline void print()
{
puts(dp[b[n]][0]?"YES":"NO");
}
int main()
{
int t=1;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}