我不好说,因为考场上我想成二分图然后就gg了

这题不难,真的不难。

∣ T i ∣ ≤ 2 |T_i|\le 2 ∣Ti​∣≤2这个性质一看就非常亲切啊,可以看成一条 a i a_i ai​到 b i b_i bi​的连边,不妨将问题做一些泛化,将 ∣ T i ∣ = 1 |T_i|=1 ∣Ti​∣=1看成连向 a i a_i ai​的自环。

那么对于一个连通块显然边的数目不超过点的数目,让我们先讨论一些比较简单的情形。

如果基环树且基环为自环,那么选择方式唯一,简单算一下即可。

如果基环树且基环不为自环,那么基环外选择方式唯一,基环内有两种方式,简单贪心一下应该不难得出答案。

如果为树,假设 { a i } \{a_i\} {ai​}已经确定了,不妨看成是以 u u u为根并且完成定向的一颗有根树, Bob \text{Bob} Bob可以将 v v v到根节点的路径上的边反向,那么相当于每个点存了一个答案,初始所有点答案都为 0 0 0, Bob \text{Bob} Bob会选择答案最小的那个点。然后 Alice \text{Alice} Alice依次加入每条边,对于没有别固定的边 ( u , v ) (u,v) (u,v),设 u u u是 v v v的父亲,如果选 v v v相当于 v v v子树外的点答案 + 1 +1 +1,如果选 u u u相当于 v v v子树内的点答案 + 1 +1 +1(称为不动点),如果有两个点 u , v u,v u,v都是翻转点,那么显然 u , v u,v u,v满足祖先关系(否则不优),而显然选深度小的点作为不动点更优,那么就做完了。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)。

总之是非常套路的题,但是不知道为啥考场上没想出来。

总之就是非常难写,今年省选代码量确实有一点点大

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define db double
#define fi first
#define se second
using namespace std;
const int N=1e6+5;
int T,n,m,fa[N],sz1[N],sz2[N],a[N][2],b[N][2];
int rt,re,pre[N],prepos[N],visit[N],task,res,dfn[N],num,home[N],cntnode;
int head[N*2],nxt[N*2],to[N*2],pos[N*2],tot;
int posedge;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
struct node{int dat,min;
}t[N<<2];
void Add(int p,int x){t[p].min+=x,t[p].dat+=x;
}
void pushup(int p){t[p].min=min(t[p<<1].min,t[p<<1|1].min);
}
void pushdown(int p){if(t[p].dat){Add(p<<1,t[p].dat),Add(p<<1|1,t[p].dat);t[p].dat=0;}
}
void upd(int p,int l,int r,int ql,int qr,int x){if(ql<=l&&r<=qr){Add(p,x);return;}int mid=l+r>>1;pushdown(p);if(ql<=mid)upd(p<<1,l,mid,ql,qr,x);if(mid<qr)upd(p<<1|1,mid+1,r,ql,qr,x);pushup(p);
}
int qry(int p,int l,int r,int ql,int qr){if(ql<=l&&r<=qr)return t[p].min;int mid=l+r>>1;pushdown(p);if(qr<=mid)return qry(p<<1,l,mid,ql,qr);if(mid<ql)return qry(p<<1|1,mid+1,r,ql,qr);return min(qry(p<<1,l,mid,ql,qr),qry(p<<1|1,mid+1,r,ql,qr));
}
void add(int x,int y,int z){to[++tot]=y,pos[tot]=z,nxt[tot]=head[x],head[x]=tot;to[++tot]=x,pos[tot]=z,nxt[tot]=head[y],head[y]=tot;
}
void unionset(int x,int y){int u=find(x),v=find(y);if(u!=v)fa[u]=v,sz1[v]+=sz1[u]+1,sz2[v]+=sz2[u];else sz1[v]++;
}
int calc(int pos,int v){assert(v);return a[pos][0]==v||a[pos][1]==v;
}
int X,Y,Z;
int check(int pos){return a[pos][0]==b[pos][0]&&a[pos][1]==b[pos][1]||a[pos][0]==b[pos][1]&&a[pos][1]==b[pos][0];
}
//fixed
void findroot(int u,int topf){visit[u]=task;for(int k=head[u];k;k=nxt[k]){if(k!=(topf^1)){int v=to[k];if(visit[v]!=task)findroot(v,k);else {rt=u;if(u==v)posedge=pos[k];}}}
}
//fixed
void dfs(int u,int topf){visit[u]=task;for(int k=head[u];k;k=nxt[k]){int v=to[k];if(k!=(topf^1)){if(visit[v]!=task){pre[v]=u,prepos[v]=pos[k],dfs(v,k);res+=calc(pos[k],v);}else if(u!=rt){assert(!re);re=u;if(check(pos[k])){Z++;}else {if(calc(pos[k],rt))X++;else if(calc(pos[k],re))Y++;}}}}
}
int solve1(int u){rt=u,re=0,task++;X=0,Y=0,Z=0,res=0,posedge=0;findroot(rt,0);if(posedge)res+=calc(posedge,rt);task++;dfs(rt,0);if(!re)return res;assert(rt!=re);while(re!=rt){int tmp=prepos[re];res-=calc(tmp,re);if(check(tmp)){Z++;}else{if(calc(tmp,re))X++;else if(calc(tmp,pre[re]))Y++;}re=pre[re];}if(X>Y)swap(X,Y);if(X+Z<=Y)return X+Z+res;return (X+Y+Z)/2+res;
}
void modify(int u,int state,int f){if(state==0){upd(1,1,m,dfn[u],dfn[u]+home[u]-1,f);}else{upd(1,1,m,dfn[u],dfn[u]+home[u]-1,-f);upd(1,1,m,1,cntnode,f);}
}
void dfs1(int u,int topf){dfn[u]=++num,home[u]=1,cntnode++;for(int k=head[u];k;k=nxt[k]){int v=to[k];if(v!=topf){dfs1(v,u),home[u]+=home[v];}}
}
void dfs2(int u,int topf,int f){for(int k=head[u];k;k=nxt[k]){int v=to[k];if(v!=topf){if(check(pos[k])){modify(v,1,f);}else if(calc(pos[k],v)){modify(v,1,f);}else if(calc(pos[k],u)){modify(v,0,f);}dfs2(v,u,f);}}
}
void dfs3(int u,int topf){res=max(res,qry(1,1,m,1,cntnode));for(int k=head[u];k;k=nxt[k]){int v=to[k];if(v!=topf){if(check(pos[k])){modify(v,1,-1);modify(v,0,1);}dfs3(v,u);if(check(pos[k])){modify(v,1,1);modify(v,0,-1);}}}
}
int solve2(int u){num=0,cntnode=0,dfs1(u,0);assert(cntnode==sz2[find(u)]);res=0;dfs2(u,0,1),dfs3(u,0),dfs2(u,0,-1);assert(t[1].min==0);return res;
}
int solve(){int tot=0;for(int i=1;i<=m;i++){if(find(i)==i){if(sz1[i]>sz2[i]){return -1;}if(sz1[i]==sz2[i])tot+=solve1(i);else tot+=solve2(i);}}return tot;
}
int main(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>T;while(T--){cin>>n>>m;tot=1;for(int i=1;i<=m;i++)head[i]=0;for(int i=1;i<=m;i++)fa[i]=i,sz1[i]=0,sz2[i]=1;for(int i=1;i<=n;i++)a[i][0]=a[i][1]=b[i][0]=b[i][1]=0;for(int i=1;i<=n;i++){int k;cin>>k;while(k--)cin>>a[i][k];}for(int i=1;i<=n;i++){int k;cin>>k;if(k==2){while(k--)cin>>b[i][k];unionset(b[i][0],b[i][1]);add(b[i][0],b[i][1],i);}else{while(k--)cin>>b[i][k];unionset(b[i][0],b[i][0]);add(b[i][0],b[i][0],i);}}cout<<solve()<<"\n";}
}

【学习笔记】[省选联考 2023] 填数游戏相关推荐

  1. P7515-[省选联考 2021A卷]矩阵游戏【差分约束】

    正题 题目链接:https://www.luogu.com.cn/problem/P7515 题目大意 有一个n∗mn*mn∗m的矩形AAA,然后给出一个(n−1)∗(m−1)(n-1)*(m-1)( ...

  2. 大连大学两日游———2021省选联考游记

    大连大学两日游---2021省选联考游记 今年高一,今年省选就是去积累大赛经验的,为明年的主场做准备.考前参加过几次学校组织的模拟赛(死难死难 ),都得了不点分,所以本来就没多大目标,不爆零就行,但是 ...

  3. 《游戏设计艺术(第2版)》——学习笔记(28)第28章 制作游戏的技术

    <游戏设计艺术(第2版)>学习笔记(28) 第28章 制作游戏的技术 终于该谈论技术了 基础性的和装饰性的 米老鼠的第一部卡通 刺猬索尼克(音速小子) 神秘岛 旅行 布娃娃物理系统(Rag ...

  4. 【NOIP2018】DAY2T2——填数游戏(轮廓线状压的dp?搜索打表)

    描述 小 D 特别喜欢玩游戏.这一天,他在玩一款填数游戏. 这个填数游戏的棋盘是一个n × m的矩形表格.玩家需要在表格的每个格子中填入一个数字(数字 0 或者数字 1),填数时需要满足一些限制. 下 ...

  5. 枚举算法5——填数游戏

    填数游戏,如图所示每个汉字代表一个数字,不同的汉字代表数字不同,要求填写这些汉字代表的数字. [分析] 从图中可以看出,共有5个汉字,每个汉字是数字0~9中的一个.显然"北"和&q ...

  6. P5023 填数游戏

    题目描述 小 D 特别喜欢玩游戏.这一天,他在玩一款填数游戏. 这个填数游戏的棋盘是一个n×m的矩形表格.玩家需要在表格的每个格子中填入 一个数字(数字 0或者数字 1),填数时需要满足一些限制. 下 ...

  7. 1908: 【18NOIP提高组】填数游戏

    [题目描述] 小 D 特别喜欢玩游戏.这一天,他在玩一款填数游戏. 这个填数游戏的棋盘是一个n×mn×m的矩形表格.玩家需要在表格的每个格子中填入一个数字(数字 00 或者数字 11),填数时需要满足 ...

  8. 170713 逆向-填数游戏

    1625-5 王子昂 总结<2017年7月13日> [连续第284天总结] A. CISCN 结合WP再战RE B. 这么久之后完整的wp终于出来了,回过头再做一遍之前的re 首先是最早放 ...

  9. 【NOIP 2018 提高组】填数游戏

    传送门 problem 小 D 特别喜欢玩游戏.这一天,他在玩一款填数游戏. 这个填数游戏的棋盘是一个 n×mn \times mn×m 的矩形表格.玩家需要在表格的每个格子中填入一个数字(数字 00 ...

最新文章

  1. Java学习总结:47(打印流)
  2. 数据依赖症:当今AI领域的核心风险
  3. Android-Presentation双屏异显-一看就懂篇
  4. 怎么UI数组惊醒初始化 c语言,C语言教案7-数组.ppt
  5. Linux如何查看进程、杀死进程、查看端口等常用命令
  6. APP元素定位操作API
  7. PHP经典算法 (转载)
  8. datagrid出现相同两组数据_数据分析之统计学
  9. mysql中存储日期的类型_选择合适的 MySQL 日期时间类型来存储你的时间
  10. wordpress 插件_如何为您的Web应用程序创建WordPress插件
  11. android tv ko,Android TV 键值修改流程
  12. 为什么没有看到webcontent_王者荣耀之战坦路玩家心理:队友为什么不支援!我想要和射手换线...
  13. Node.js webpack webpack-dev-server
  14. 百度云安装WordPress,提示数据库连接错误!
  15. 零基础学习Java的路线,学完上岸BAT!
  16. librdkafka安装步骤
  17. Beta冲刺第二周王者荣耀交流协会第五次会议
  18. node.js 下载速度慢问题
  19. 平台建设的7大问题:蚂蚁AI平台实践深度总结
  20. peewee的使用与异步peewee-async在tornado中的使用总结

热门文章

  1. 线上nacos命名空间误删如何找回 实践笔记
  2. PS制作红色拟物化时钟icon图标
  3. IDEA 同时打开两个项目
  4. mp4文档ISO/IEC 14496 part 12解读
  5. 幻影坦克制作流程和步骤
  6. 单源最短路和多源最短路
  7. Java 近闻:JDK 20、新的 JEP 草案、JobRunr 6.0、GraalVM 22.3.1
  8. Yunzai-Bot(云崽) | Linux Docker保姆级安装教程
  9. Jupyter Notebook 主题库 jupyterthemes 安装和使用方法
  10. 数学建模【微分方程模型(介绍、分析方法、数值模拟、传染病问题的建模和分析、经济增长模型、人口增长预测和控制模型)】