其他分享
首页 > 其他分享> > chess

chess

作者:互联网

有一个 \(n×n\) 的棋盘上有 \(k\) 个车(棋子),每个车都有一个权值 \(w_i\) 。

我们进行如下定义:

一个车能到达除了它自己所在的格子以外它所在行和列的所有其它格子。

如果所有能到达格子 \((x,y)\) 的车的权值异或和大于 0 ,就称其为被控制的。

在初始局面下,有 \(q\) 次操作,每次把一个车从一个位置移动到另外一个位置。在每次操作后请输出被控制的格子数。

输入格式
第一行三个整数, \(n,k,q\) 。

接下来的 \(k\) 行,每行三个整数 \(x_i,y_i,w_i\) ,表示一个在 (\(x_i\),\(y_i\)) 格子,权值为 \(w_i\) 的车。

接下来的 \(q\) 行,每行四个整数 \(x1,y1,x2,y2\) ,表示一个 (\(x1\),\(y1\)) 格子上的车被移动到了 (\(x2\),\(y2\)) 上。

保证同一时刻不会有两个车在同一格子上。

输出格式
输出共 \(q\) 行,第 $i $行表示第 \(i\) 次操作后棋盘上被控制的格子数。

样例输入
input

2 2 2
1 1 1
2 2 2
2 2 2 1
1 1 1 2

output

4
2

数据范围
对于 40% 的数据, \(n,k≤100\) 。

对于 100% 的数据, \(n≤10^9,k≤10^5,q≤10^5,wi≤10^9\) 。

时间限制: 3s
空间限制: 256MB

可以到达一个点的有两种位置,要不\(x\)坐标相等的,要不\(y\)坐标相等的。那么我们可以用一个map \(g\)统计在所有的\(x\)坐标和所有的\(y\)坐标构成的竖线横线里面,总异或值是多少,一个位置\((x,y)\)不被控制的条件就是\(g_x\oplus g_y=0\),即\(g_x=g_y\).要知道有多少个点相同。正难则反,我们统计总共有多少个位置不被控制,我们还要统计每一种异或和出现的数量,然后相乘相加就是总共的不被控制的数量。

移动旗子可以拆成加一个旗子和减一个旗子,然而这两种操作的实质是一样的,都是在这个位置改变。首先我们要在\(g\)中改变这一行和这一列的总异或和,然后要统计有多少个相同,改之前减去1,改后在新的异或和加上1.

最关键的是如何实时维护答案。在代码中详细解释。

#include<cstdio>
#include<map>
using namespace std;
const int N=1e5+5;
long long M=1e9+5;
int k,q,x,y,z,w;
map<long long,int>t;
map<int,int>h,l,ch,cl;
long long ret,n; 
int add(int x,int y,int w)
{
	ret-=cl[h[x]]+ch[l[y]];
	//一开始答案加上$cl[h[x]]*ch[h[x]]+ch[l[y]]*cl[l[y]];
	//ch[h[x]]-1,cl[l[x]]-1后,答案减去cl[h[x]]+ch[l[y]]
	ch[h[x]]--,cl[l[y]]--;
	h[x]^=w,l[y]^=w;
	ch[h[x]]++,cl[l[y]]++;
	ret+=cl[h[x]]+ch[l[y]];
}
int main()
{
	scanf("%lld%d%d",&n,&k,&q);
	ret=n*n;
	cl[0]=ch[0]=n;
	for(int i=1;i<=k;i++)
		scanf("%d%d%d",&x,&y,&w),t[x*M+y]=w,add(x,y,w);
	while(q--)
		scanf("%d%d%d%d",&x,&y,&z,&w),add(x,y,t[x*M+y]),add(z,w,t[x*M+y]),t[z*M+w]=t[x*M+y],t[x*M+y]=0,printf("%lld\n",n*n-ret);
	return 0;
}

标签:ch,格子,cl,int,long,异或,chess
来源: https://www.cnblogs.com/mekoszc/p/16208558.html