QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#654956 | #7755. Game on a Forest | Tomgao4116 | WA | 5ms | 15760kb | C++20 | 3.2kb | 2024-10-18 23:13:41 | 2024-10-18 23:13:42 |
Judging History
answer
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<long long,long long> pll;
vector<ll> a[500005];
ll vis[500005];
ll cnt[500005];
ll sum[500005];
ll pre[500005];
ll f[500005];
ll d[500005];
//每个子树点的异或值:sum[i]
//子树下面多个子树合并的异或值:pre[i]
//以点i为根的子树节点个数cnt[i]
//标号:f[i]:代表第i个点是属于那个点为根的子树:
//标号dfs:
ll val=0,ans=0;
void dfs1(ll ver){
vis[ver]=1;
for(int i=0;i<a[ver].size();i++){
ll nxt=a[ver][i];
if(vis[nxt]==0){
f[nxt]=f[ver];
dfs1(nxt);
}
}
}
//预处理dfs
void dfs2(ll ver){
cnt[ver]=1;
pre[ver]=0;
vis[ver]=1;
for(int i=0;i<a[ver].size();i++){
ll nxt=a[ver][i];
if(vis[nxt]==0){
dfs2(nxt);
cnt[ver]+=cnt[nxt];
pre[ver]^=sum[nxt];
}
}
//下面子节点个数是奇数:下面sg值为1
if(cnt[ver]%2==1){
sum[ver]=1;
//下面子节点个数是偶数:下面sg值为2:
}else{
sum[ver]=2;
}
}
void dfs3(ll ver,ll root){
vis[ver]=1;
// cout<<"ver: "<<ver<<endl;
for(int i=0;i<a[ver].size();i++){
ll nxt=a[ver][i];
if(vis[nxt]==0){
dfs3(nxt,root);
ll down=cnt[nxt];
ll up=cnt[root]-cnt[nxt];
// cout<<up<<" "<<down<<" "<<ver<<" "<<nxt<<endl;
if(down%2==1){
down=1;
}else{
down=2;
}
if(up%2==1){
up=1;
}else{
up=2;
}
// cout<<up<<" "<<down<<endl;
//如果删去这条边后的状态异或和能赢:----代表第二个要输:所以这时候的异或和要为0 对答案的贡献+1;
if((val^sum[root]^up^down)==0)ans++;
}
}
}
void dfs4(ll ver,ll root){
vis[ver]=1;
ll up=cnt[root]-cnt[ver];
if(up%2==1){
up=1;
}else if(up%2==0&&up>0){
up=2;
}
// cout<<"ver: "<<ver<<" "<<up<<endl;
//如果是最下面叶子节点:
if(a[ver].size()==0){
if(val^sum[root]^up==0)ans++;
}
//如果是其他节点:
for(int i=0;i<a[ver].size();i++){
ll nxt=a[ver][i];
if(vis[nxt]==0){
dfs4(nxt,root);
if((val^sum[root]^up^pre[ver])==0){
//cout<<"ver: "<<ver<<" "<<nxt<<" :"<<val<<" "<<sum[root]<<" "<<up<<" "<<pre[ver]<<endl;
ans++;
}
}
}
}
int main(){
ll n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++){
ll u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
//dfs:判断每个节点属于哪个子树+做好根节点的标号:
for(int i=1;i<=n;i++){
if(!vis[i]){
dfs1(i);
}
}
memset(vis,0,sizeof(vis));
//1:先预处理出树上的前缀异或和+子树节点数目:
for(int i=1;i<=n;i++){
//从森林中每个子树的根节点进入dfs预处理:
// cout<<i<<" "<<f[i]<<endl;
if(!vis[i]&&f[i]==i){
dfs2(i);
if(cnt[i]%2==1){
val^=1;
}else{
val^=2;
}
}
}
//1:枚举删边:
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
if(!vis[i]&&f[i]==i){
dfs3(i,i);
}
}
// cout<<ans<<endl;
//2:枚举删点:
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
//1:1个点单独处理:
if(cnt[i]==1){
if((val^1)==0)ans++;
continue;
}
if(!vis[i]&&f[i]==i){
dfs4(i,i);
}
}
cout<<ans;
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 0
Wrong Answer
time: 5ms
memory: 15760kb
input:
3 1 1 2
output:
1
result:
wrong answer 1st numbers differ - expected: '2', found: '1'