ZJNU - 1707 TOPOVI

1.题面

http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=1707

2.题意

有一个n×n的棋盘国际象棋,其中每个格子初始数值都为0,。你要在棋盘上摆放车(rook),每个车都有一个数值power,它所在的行和列就是它的power的作用范围,作用的方式是他给行和列的每个格子(除了自身所在格子)都异或(^)上自己的power。所有异或值不为0的格子都被视为是遭受攻击的格子。

输入中n,k,p分别为棋盘的边长,棋子的个数,操作的个数。

然后k行告诉你k个棋子的位置和power。

随后p行每行都是一个移动操作。告诉你将一个棋子移动到另一个位置。

要求输出每一次移动后,受攻击的格子的个数。

3.解题思路

异或操作是一个性质很好的操作。满足(a^k)^a = k。基于异或操作的这种性质,我们可以推出以下结论:

        1.在某一个位置移走一个棋子其实相当于在这个位置重新摆放(重叠)一个这个棋子。

        2.在一个位置摆放一个棋子等同于对行和列都异或上自己的power值。因为行列各摆放一个对他们交点的作用会相互抵消。

第二条性质告诉你摆放操作可以视为对行和列的两个独立操作,第一条性质告诉你移走一个棋子和摆放一个棋子是本质上相同的操作。

因为行操作和列操作的对称性,我们只需要思考对行施加一个操作的时候需要怎么做。

ll ans;						/*the number of position under attack*/
map<int,int> cntcol,cntrow;      /*cntcol[i]: There is cntcol[i] columns of power i*/
map<int,int> col,row;                 /*col[i]   : The ith col is of power col[i]*/
typedef pair<int,int> coord;
map<coord,int> rook;                /*rook[coord(x,y)]: the rook in (x,y) is of power rook[coord(x,y)]*/


应该都看得懂的

修改操作是:

	ans -= n - cntcol[row[r]];
	cntrow[row[r]]--;
	row[r] ^= power;
	cntrow[row[r]]++;
	ans += n - cntcol[row[r]];

具体的很难用话讲,不写了(T_T)

4.解题代码

/*****************************************************************
    > File Name: tmp.cpp
    > Author: Uncle_Sugar
    > Mail: uncle_sugar@qq.com
    > Created Time: 2016年03月25日 星期五 18时48分33秒
*****************************************************************/
# include <cstdio>
# include <cstring>
# include <cmath>
# include <cstdlib>
# include <climits>
# include <iostream>
# include <iomanip>
# include <set>
# include <map>
# include <vector>
# include <stack>
# include <queue>
# include <algorithm>
using namespace std;

const int debug = 1;
const int size  = 5000 + 10; 
const int INF = INT_MAX>>1;
typedef long long ll;


int n,k,p;
ll ans;						/*the number of position under attack*/
map<int,int> cntcol,cntrow;      /*cntcol[i]: There is cntcol[i] columns of power i*/
map<int,int> col,row;                 /*col[i]   : The ith col is of power col[i]*/
typedef pair<int,int> coord;
map<coord,int> rook;                /*rook[coord(x,y)]: the rook in (x,y) is of power rook[coord(x,y)]*/

void putrook(int r,int c,int power){
	ans -= n - cntcol[row[r]];
	cntrow[row[r]]--;
	row[r] ^= power;
	cntrow[row[r]]++;
	ans += n - cntcol[row[r]];

	ans -= n - cntrow[col[c]];
	cntcol[col[c]]--;
	col[c] ^= power;
	cntcol[col[c]]++;
	ans += n - cntrow[col[c]];

	rook[coord(r,c)] ^= power;
}
int main()
{
	std::ios::sync_with_stdio(false);cin.tie(0);
	int i,j;
	while (cin >> n >> k >> p){
		ans = 0;rook.clear();
		cntcol.clear();cntrow.clear();
		col.clear();row.clear();
		cntrow[0] = cntcol[0] = n;
		while (k--){
			int r,c,v;
			cin >> r >> c >> v;
			putrook(r,c,v);
		}
		while (p--){
			int r1,c1,r2,c2;
			cin >> r1 >> c1 >> r2 >> c2;
			int rookpower = rook[coord(r1,c1)];
			putrook(r1,c1,rookpower);
			putrook(r2,c2,rookpower);
			cout << ans << '\n';
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值