【loj#2524】【bzoj5303】 [Haoi2018]反色游戏(圆方树)
题意中的游戏方案可以转化为一个异或方程组的解,将边作为变量,点作为方程,因此若方程有解,方程的解的方案数就是2的自由元个数次方。我们观察一下方程,就可以发现自由元数量=边数-点数+连通块数,或者换句话说,若对原图的每个联通块指定一棵生成树,那么确定了生成树之外的边是否进行操作,那么生成树内的边的操作方案就是一定存在并唯一确定的。
那么我们就只需要判断一下什么样的图无解。我们发现每对一条边进行操作,原图内的黑点数量奇偶性不变,那么我们只需判断图中的是否存在某个联通块有奇数个黑点,若存在即无解。
加上了删点操作后,我们可以用圆方树来维护连通块信息。因为圆方树的连通性与原图上的连通性相互对应,删除单个点之后,原图被新分成的连通块就是圆方树删除对应点的连通块,那么使用圆方树就可以快速维护删除单个点的连通块信息。
代码:
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- #include<cstdlib>
- #include<algorithm>
- #define ll long long
- #define inf 0x3f3f3f3f
- #define mod 1000000007
- #define maxn 200010
- inline ll read()
- {
- ll x=; char c=getchar(),f=;
- for(;c<''||''<c;c=getchar())if(c=='-')f=-;
- for(;''<=c&&c<='';c=getchar())x=x*+c-'';
- return x*f;
- }
- inline void write(ll x)
- {
- static int buf[],len; len=;
- if(x<)x=-x,putchar('-');
- for(;x;x/=)buf[len++]=x%;
- if(!len)putchar('');
- else while(len)putchar(buf[--len]+'');
- }
- inline void writeln(ll x){write(x); putchar('\n');}
- inline void writesp(ll x){write(x); putchar(' ');}
- struct edge{
- int to,nxt;
- };
- struct Graph{
- edge e[*maxn];
- int fir[*maxn],deg[*maxn];
- int tot;
- inline void clear()
- {
- memset(fir,,sizeof(fir)); tot=;
- memset(deg,,sizeof(deg));
- }
- inline void add_edge(int x,int y)
- {
- e[tot].to=y; e[tot].nxt=fir[x]; fir[x]=tot++;
- ++deg[x];
- }
- }G,T;
- int dfn[maxn],low[maxn],st[maxn],ans[maxn];
- int val[*maxn],size[*maxn],fa[*maxn],rt[*maxn];
- char s[maxn];
- int n,m,tot,tp,cnt;
- inline ll power(ll a,ll b)
- {
- ll ans=;
- for(;b;b>>=,a=a*a%mod)
- if(b&)ans=ans*a%mod;
- return ans;
- }
- void tarjan(int now,int last)
- {
- dfn[now]=low[now]=++tot; st[++tp]=now;
- for(int i=G.fir[now];~i;i=G.e[i].nxt)
- if(i!=(last^)){
- if(!dfn[G.e[i].to]){
- tarjan(G.e[i].to,i);
- low[now]=std::min(low[now],low[G.e[i].to]);
- if(low[G.e[i].to]>=dfn[now]){
- ++cnt;
- T.add_edge(now,cnt); T.add_edge(cnt,now);
- do{
- T.add_edge(st[tp],cnt); T.add_edge(cnt,st[tp]);
- }while(st[tp--]!=G.e[i].to);
- }
- }
- else low[now]=std::min(low[now],dfn[G.e[i].to]);
- }
- }
- void dfs(int now,int root)
- {
- rt[now]=root;
- size[now]=val[now];
- for(int i=T.fir[now];~i;i=T.e[i].nxt)
- if(T.e[i].to!=fa[now]){
- fa[T.e[i].to]=now;
- dfs(T.e[i].to,root);
- size[now]+=size[T.e[i].to];
- }
- }
- void work()
- {
- n=read(); m=read();
- G.clear();
- for(int i=;i<=m;i++){
- int x=read(),y=read();
- G.add_edge(x,y); G.add_edge(y,x);
- }
- scanf("%s",s);
- memset(val,,sizeof(val));
- for(int i=;i<=n;i++)
- val[i]=(s[i-]=='');
- T.clear();
- memset(dfn,,sizeof(dfn));
- memset(low,,sizeof(low));
- tot=tp=; cnt=n;
- for(int i=;i<=n;i++)
- if(!dfn[i]){
- tarjan(i,-);
- fa[i]=-;
- dfs(i,i);
- }
- int odd=,block=;
- for(int i=;i<=n;i++)
- if(fa[i]==-)odd+=(size[i]&),++block;
- ans[]=(odd?:power(,m-n+block));
- for(int i=;i<=n;i++){
- odd-=(size[rt[i]]&);
- int flag=;
- for(int j=T.fir[i];~j;j=T.e[j].nxt)
- if(T.e[j].to!=fa[i]&&(size[T.e[j].to]&)){
- flag=; break;
- }
- if(odd||!flag||((size[rt[i]]-size[i])&))ans[i]=;
- else ans[i]=power(,(m-G.deg[i])-(n-)+(block+T.deg[i]-));
- odd+=(size[rt[i]]&);
- }
- for(int i=;i<=n;i++)
- writesp(ans[i]);
- putchar('\n');
- }
- int main()
- {
- int T=read();
- while(T--)work();
- return ;
- }
反色游戏
【loj#2524】【bzoj5303】 [Haoi2018]反色游戏(圆方树)的更多相关文章
- [BZOJ5303] [HAOI2018] 反色游戏
题目链接 LOJ:https://loj.ac/problem/2524 BZOJ:https://lydsy.com/JudgeOnline/problem.php?id=5303 洛谷:https ...
- [BZOJ5303][HAOI2018]反色游戏(Tarjan)
暴力做法是列异或方程组后高斯消元,答案为2^自由元个数,可以得60分.但这个算法已经到此为止了. 从图论的角度考虑这个问题,当原图是一棵树时,可以从叶子开始唯一确定每条边的选择情况,所以答案为1. 于 ...
- 【BZOJ5303】[HAOI2018]反色游戏(Tarjan,线性基)
[BZOJ5303][HAOI2018]反色游戏(Tarjan,线性基) 题面 BZOJ 洛谷 题解 把所有点全部看成一个\(01\)串,那么每次选择一条边意味着在这个\(01\)串的基础上异或上一个 ...
- bzoj 5393 [HAOI2018] 反色游戏
bzoj 5393 [HAOI2018] 反色游戏 Link Solution 最简单的性质:如果一个连通块黑点个数是奇数个,那么就是零(每次只能改变 \(0/2\) 个黑点) 所以我们只考虑偶数个黑 ...
- P4494 [HAOI2018]反色游戏
P4494 [HAOI2018]反色游戏 题意 给你一个无向图,图上每个点是黑色或者白色.你可以将一条边的两个端点颜色取反.问你有多少种方法每个边至多取反一次使得图上全变成白色的点. 思路 若任意一个 ...
- bzoj5315/luoguP4517 [SDOI2018]战略游戏(圆方树,虚树)
bzoj5315/luoguP4517 [SDOI2018]战略游戏(圆方树,虚树) bzoj Luogu 题目描述略(太长了) 题解时间 切掉一个点,连通性变化. 上圆方树. $ \sum |S| ...
- BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)
Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...
- [SDOI2018]战略游戏 圆方树,树链剖分
[SDOI2018]战略游戏 这题是道路相遇(题解)的升级版,询问的两个点变成了\(S\)个点. LG传送门 还是先建出圆方树,考虑对于询问的\(S\)个点,答案就是圆方树上能包含这些点的最小连通块中 ...
- LOJ.2587.[APIO2018]铁人两项Duathlon(圆方树)
题目链接 LOJ 洛谷P4630 先对这张图建圆方树. 对于S->T这条(些)路径,其对答案的贡献为可能经过的所有点数,那么我们把方点权值设为联通分量的大小,可以直接去求树上路径权值和. 因为两 ...
随机推荐
- pcntl_fork()函数说明
pcntl_fork()函数复制了当前进程的PCB,并向父进程返回了派生子进程的pid,父子进程并行,打印语句的先后完全看系统的调度算法,打印的内容控制则靠pid变量来控制.因为我们知道pcntl_f ...
- 找回Firefox4的状态栏!Status-4-Evar扩展
Status-4-Evar这个扩展能让Firefox4故意移除的状态栏给找回来!官方下载地址为:https://addons.mozilla.org/zh-CN/firefox/addon/23528 ...
- 【leetcode_easy】532. K-diff Pairs in an Array
problem 532. K-diff Pairs in an Array 题意:统计有重复无序数组中差值为K的数对个数. solution1: 使用映射关系: 统计数组中每个数字的个数.我们可以建立 ...
- .Netcore 2.0 Ocelot Api网关教程(10)- Headers Transformation
本文介绍Ocelot中的请求头传递(Headers Transformation),其可以改变上游request传递给下游/下游response传递给上游的header. 1.修改ValuesCont ...
- Java工程师学习指南第8部分:分布式系统理论与实践
本文整理了微信公众号[Java技术江湖]发表和转载过的分布式相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧. 细聊分布式ID生成方法 近期面试Java后端的一些感悟 本专栏介绍分布式的 ...
- 集群架构04·NFS服务,环境安装
初识 网络文件系统Netwrok File System,类似于wiin10的网络共享 功能:通过网络让不同主机系统之间可以共享文件或目录 客户端通过挂载的方式将服务器端共享的目录挂载到本地系统. 集 ...
- Spring A 标签链接使用
1.示例 <a th:href="@{/edit/{id}(id=${user.id})}">修改</a> 以@开头前面的{id}是占位符,后面的(id=$ ...
- 洛谷 题解 P2280 【[HNOI2003]激光炸弹】
一道很好的二维前缀和模板题. 什么是二维前缀和? 从这张图可以看出前缀和的求法: Map[i][j]=Map[i-1][j]+Map[i][j-1]-Map[i-1][j-1]+Map[i][j]; ...
- [学习笔记] 在Eclips 中导出项目
有时候需要将自己完成的项目分享给别人,可以按如下步骤操作: 选择要导出的内容,设置导出的文件名. 然后点击,Finish 即可. 然后到d:\tmp 会看到文件:Hibernat_demo_001.z ...
- 如何克服社交恐惧症?zz
zhang Bavol 清华大学核能与新能源技术研究院——核科学与技术/电子爱好者 你说的这个恐惧症我也有一点点,不过现在我是只对那种不是很熟悉的七姑八婆之类的亲戚才会有这种憋屈感觉,对朋友和 ...