题目思路
因为每次只能向下和向右走,那么我们判断一个点是否能够到达就去判断它左边和上面是否都无法到达就好了。
我们将k个无法走到的点排序后,分开处理每一行的情况。
如果我们枚举到了第i层,他的第j个位置是无法走到的,那么我们需要找到的就是第i-1层中从j+1位置开始第一个可以走到的点。
我们处理情况需要用到的就是区间修改和区间查询
ac代码
int n,m,k;
vector<int>vec[maxn];
ll t[maxn<<2][3],lz[maxn<<2][3];
void pushdown(int rt,int l,int r,int now)
{
if(lz[rt][now]!=-1)
{
int mid=(r+l)>>1;
lz[lson][now]=lz[rt][now]*(mid-l+1);
lz[rson][now]=lz[rt][now]*(r-mid);
t[lson][now]=lz[rt][now]*(mid-l+1);
t[rson][now]=lz[rt][now]*(r-mid);
lz[rt][now]=-1;
}
}
void update(int now,int rt,int l,int r,int L,int R,int w)
{
if(L<=l&&r<=R)
{
t[rt][now]=w*(r-l+1);
lz[rt][now]=w*(r-l+1);
return;
}
int mid=(l+r)>>1;
pushdown(rt,l,r,now);
if(mid>=L)
update(now,lson,l,mid,L,R,w);
if(mid<R)
update(now,rson,mid+1,r,L,R,w);
t[rt][now]=t[rson][now]+t[lson][now];
}
int query(int now,int rt,int l,int r,int L,int R)
{
if(l==r)
{
if(t[rt][now])return l;
else return -1;
}
int mid=(l+r)>>1;
pushdown(rt,l,r,now);
int ans=-1;
if(mid>=L&&t[lson][now])
ans=query(now,lson,l,mid,L,R);
if(ans!=-1)return ans;
if(mid<R&&t[rson][now])
ans=query(now,rson,mid+1,r,L,R);
return ans;
}
void build(int rt,int l,int r)
{
lz[rt][1]=-1;
lz[rt][0]=-1;
t[rt][1]=0;
t[rt][0]=0;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
}
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vec[x].push_back(y);
}
for(int i=1;i<=n;i++)
{
vec[i].push_back(0);
vec[i].push_back(m+1);
sort(vec[i].begin(),vec[i].end());
}
build(1,1,n);
int now=0;
ll ans=0;
if(vec[1].size()==2)
{
update(0,1,1,m,1,m,1);
ans+=m;
}else
{
update(0,1,1,m,1,vec[1][1]-1,1);
ans+=vec[1][1]-1;
}
//printf("%lld\n",ans);
for(int i=2;i<=n;i++)
{
for(int j=0;j<vec[i].size()-1;j++)
{
int l=vec[i][j]+1,r=vec[i][j+1]-1;
int x=query(now,1,1,m,l,r);
if(l<=r&&x!=-1)
{
ans+=r-x+1;
update(now^1,1,1,m,x,r,1);
}
}
update(now,1,1,m,1,m,0);
now=now^1;
}
printf("%lld\n",ans);
for(int i=1;i<=n;i++)
{
vec[i].clear();
}
}
}