DTOJ #2488. 象棋游戏(topovi)

【题目描述】

Mirko是一个象棋爱好者,他在一个 $N \times N$ 的棋盘上放置 $K$ 个车,游戏规则如下:

- 每个车有一个权值。

- 每个车可以看到它所在的行和列上的所有其他格子(不包括本身)。

- 一个格子被攻击当且仅当它所能看到的所有车的权值异或值大于 $0$ 。

现在,Mirko要对棋盘上的一些车进行 $P$ 次移动,每个车可以移动到棋盘上的任意一个空格子(不只是行和列上的移动),请你帮忙计算对于每次移动后棋盘上有多少个格子被攻击

【输入格式】

第一行包含三个整数 $N,K,P$。

接下来 $K$ 行,每行包含三个整数 $R,C,X$,表示在 $(R,C)$ 位置上的车的权值为 $X$ 。

接下来 $P$ 行,每行包含四个整数 $R1,C1,R2,C2$,表示将 $(R1,C1)$ 位置上的车移动到$(R2,C2)$。

数据保证不会出现两个车在同一格子。

【输出格式】

输出包含 $P$ 行,第 $i$ 行表示经过 $i$ 次移动之后,棋盘上有多少个格子被攻击。

【样例】

样例输入
3 3 4
1 1 1
2 2 2
2 3 3
2 3 3 3
3 3 3 1
1 1 1 2
3 1 3 2

样例输出
6
7
7
9

【数据范围与提示】

对于25%数据,$1 \le N,K \le 100$。

对于100%数据,$1 \le N \le 1000000000, 1 \le K \le 100000, 1 \le P \le 100000, 1 \le R,C \le N, 1 \le X \le 1000000000 $。

【题解】

难得有道良心水题。。。考查 $STL$ 的基础应用。

显然行与列异或和相同的位置就不会被攻击,用 $map$ 维护每行每列的异或和,并维护行与列每种异或和的个数即可。

【代码】

#include<bits/stdc++.h>
inline int read ( void )
{
	int x=0;char ch;bool f=true;
	while ( !isdigit(ch=getchar()) ) if ( ch=='-' ) f=false;
	for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
	return f ? x : -x ;
}
int n,k,p,val[100010];
long long ans;
std::map<std::pair<int,int>,int> id;
std::map<int,int> cntx,cnty,sumx,sumy;
inline void Insert ( int x,int y,int val )
{
	cntx[sumx[x]]--;cnty[sumy[y]]--;
	ans+=cnty[sumx[x]]+cntx[sumy[y]];
	sumx[x]^=val;sumy[y]^=val;
	ans-=cnty[sumx[x]]+cntx[sumy[y]];
	cntx[sumx[x]]++;cnty[sumy[y]]++;
}
signed main()
{
	n=read();k=read();p=read();cntx[0]=cnty[0]=n;
	for ( int i=1;i<=k;i++ ) { int r=read(),c=read();val[i]=read();id[std::make_pair(r,c)]=i;Insert(r,c,val[i]); }
	while ( p-- )
	{
		int r1=read(),c1=read(),r2=read(),c2=read(),i=id[std::make_pair(r1,c1)];id[std::make_pair(r1,c1)]=0;
		Insert(r1,c1,val[i]);Insert(r2,c2,val[i]);id[std::make_pair(r2,c2)]=i;printf("%lld\n",ans);
	}
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/RenSheYu/p/11317027.html