[GCJ Farewell Round #3] The Decades of Coding Competitions 题解
考虑一个
证明:考虑一个不必经过的颜色
视
放代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
typedef tuple<int,int,int> tpi;
const int C=100;
namespace IAOI_lib{
template<typename T> class dsu{
private:
vector<T> a;
vector<int> s;
public:
dsu(int n=2e5){
a.resize(n),s.resize(n,1);
iota(a.begin(),a.end(),0);
}
T leader(T x){
return a[x]==x?x:a[x]=leader(a[x]);
}
inline int size(T x){
return s[leader(x)];
}
inline void merge(T x,T y){
x=leader(x),y=leader(y);
if(x==y)return;
if(s[x]>s[y])swap(x,y);
s[y]+=s[x],a[x]=y;
}
inline bool same(T x,T y){
return leader(x)==leader(y);
}
}; // 并查集模板
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int tt; cin>>tt;
for(int t=1;t<=tt;t++){
int n,m,q,c=0; cin>>n>>m>>q;
vector<tpi> e(m);
vector<vector<pii> > g(n);
for(auto &[u,v,c]:e){
cin>>u>>v>>c,u--,v--,c--;
g[u].emplace_back(v,c);
g[v].emplace_back(u,c);
}
vector d(C,IAOI_lib::dsu<int>(n));
// 每个颜色开一个并查集维护
for(int i=0;i<C;i++)
for(auto [u,v,c]:e)
if(c!=i)d[i].merge(u,v);
vector<int> p(n,-1);
vector h(n,vector<bool>(C));
for(int s=0;s<n;s++)
if(p[s]<0){
queue<int> q; q.emplace(p[s]=s);
while(!q.empty()){
int u=q.front(); q.pop();
for(auto [i,w]:g[u]){
if(p[i]<0)q.emplace(i);
h[p[i]=s][w]=true;
}
}
} // 搜连通块,顺带得出其中有哪几种颜色
while(q--){
int u,v,w=0; cin>>u>>v,u--,v--;
if(p[u]!=p[v])continue;
for(int i=0;i<C;i++)
w^=h[p[u]][i];
if(w){c++; continue;}
for(int i=0;i<C;i++)
if(h[p[u]][i]&&d[i].same(u,v)){c++; break;}
// 判断是否有不必经过的颜色存在
}
cout<<"Case #"<<t<<": "<<c<<'\n';
}
return 0;
}