P6532 [COCI 2015/2016 #1] TOPOVI
思路
删掉 \((r_1,c_1)\) 位置上值为 \(val\) 的棋子相当于再在原处放置一个相同的棋子使之异或后为 \(0\),故只需考虑放置新棋子后的影响。
显然一个棋子无法被攻击的充要条件是其所在行的异或和等于所在列的异或和,故使用 \(rval,cval\) 维护行和列的异或和,\(rcnt,ccnt\) 维护异或和为 \(val\) 的行和列数量。每次在 \((r,c)\) 放置一个值为 \(val\) 的新棋子的时候,所有异或和为 \(rval_r\) 的列与 \(r\) 行的交点都将由无法被攻击转为可被攻击,这部分贡献需要加上;同时,所有异和为 \(rval_r \oplus val\) 的列与 \(r\) 行的交点将由可被攻击转为不可被攻击,需要减去其数量。
代码实现上注意两种贡献计算的先后顺序,建议使用 unordered_map,比 map 更快一点。同时注意 pair 作为键值类型需要手写哈希函数。
Code
#include<iostream>
#include<utility>
#include<algorithm>
#include<unordered_map>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
struct PairHash
{
template<class T1,class T2>
size_t operator()(const pair<T1,T2> &x)const
{
hash<T1>h1;
hash<T2>h2;
return h1(x.first)^h2(x.second);
}
};
int n,k,Q;
long long ans=0;
unordered_map<int,int>rval,cval,rcnt,ccnt;
unordered_map<pair<int,int>,int,PairHash>Chequer;
void Put_Chequer(int r,int c,int val)
{
ans-=(n-ccnt[rval[r]])+(n-rcnt[cval[c]]);
rcnt[rval[r]]--,rcnt[rval[r]^=val]++;
ccnt[cval[c]]--,ccnt[cval[c]^=val]++;
ans+=(n-ccnt[rval[r]])+(n-rcnt[cval[c]]);
Chequer[{r,c}]^=val;
}
int main()
{
IOS;
cin>>n>>k>>Q;
rcnt[0]=ccnt[0]=n;
while(k--)
{
int r,c,val;
cin>>r>>c>>val;
Put_Chequer(r,c,val);
}
while(Q--)
{
int r1,c1,r2,c2,val;
cin>>r1>>c1>>r2>>c2;
val=Chequer[{r1,c1}];
Put_Chequer(r1,c1,val);
Put_Chequer(r2,c2,val);
cout<<ans<<'\n';
}
return 0;
}
完结撒花~
浙公网安备 33010602011771号