博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P4494 [HAOI2018]反色游戏(tarjan)
阅读量:5797 次
发布时间:2019-06-18

本文共 2662 字,大约阅读时间需要 8 分钟。

题面

题解

我们先来考虑一个联通块,这些关系显然可以写成一个异或方程组的形式,形如\(\oplus_{e\in edge_u}x_e=col_u\)

如果这个联通块的黑色点个数为奇数,那么显然这个方程是无解的

证明:每条边都在方程组的左边出现了两次,左边全部异或起来为\(0\),右边全部异或起来为\(1\),显然无解

那么如果这个方程组有解,解的个数就是\(2^{自由元数目}\)

我们随便求出这个联通块的一棵生成树,把所有树边当成自由元,容易发现对于非树边的每一种选法,树边都有一种唯一对应的选择方案使其合法,设这个联通块边数为\(m\),点数为\(n\),方案数就是\(2^{m-n+1}\)

进一步可得知\(c\)个联通块的方案数为\(2^{m-n+c}\)次,且与联通块内部连边无关

然后是对于每个点的询问,先判一下删掉之后的联通块中是否会有奇数个黑色点,如果合法的话就减去它周围的边数减去它自己的点数再加上新的联通块数即可

//minamoto#include
#define R register#define fp(i,a,b) for(R int i=(a),I=(b)+1;i
I;--i)#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)template
inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}using namespace std;char buf[1<<21],*p1=buf,*p2=buf;inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}int read(){ R int res,f=1;R char ch; while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1); for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0'); return res*f;}int read(char *s){ R int len=0;R char ch;while(((ch=getc())>'1'||ch<'0')); for(s[++len]=ch;(ch=getc())>='0'&&ch<='1';s[++len]=ch); return s[len+1]='\0',len;}char sr[1<<21],z[20];int C=-1,Z=0;inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}void print(R int x){ if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]=' ';}const int N=1e5+5,P=1e9+7;struct eg{int v,nx;}e[N<<1];int head[N],tot;inline void Add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}int dfn[N],low[N],sz[N],deg[N],ok[N],cut[N],rt[N],bin[N],sub[N];char s[N];int n,m,u,v,tim,Rt,cnt,odd;void tarjan(int u,int fa){ sz[u]=s[u]-'0',dfn[u]=low[u]=++tim,ok[u]=cut[u]=sub[u]=0,rt[u]=Rt; go(u)if(!dfn[v]){ tarjan(v,u),sz[u]+=sz[v],cmin(low[u],low[v]); low[v]>=dfn[u]?++cut[u],ok[u]|=(sz[v]&1),sub[u]+=sz[v]:0; }else if(v!=fa)cmin(low[u],dfn[v]); !fa?--cut[u]:0;}void clr(){ memset(dfn,0,sizeof(int)*(n+1)),tim=0; memset(head,0,sizeof(int)*(n+1)),tot=0; memset(deg,0,sizeof(int)*(n+1));}int main(){// freopen("testdata.in","r",stdin); bin[0]=1;fp(i,1,1e5)bin[i]=(bin[i-1]<<1)%P; for(int T=read();T;--T){ n=read(),m=read(); fp(i,1,m)u=read(),v=read(),++deg[u],++deg[v],Add(u,v),Add(v,u); read(s),cnt=m-n,odd=0; fp(i,1,n)if(!dfn[i])Rt=i,tarjan(i,0),++cnt,odd+=(sz[i]&1); print(odd?0:bin[cnt]); fp(i,1,n)print((ok[i]||(odd-(sz[rt[i]]&1))||((sz[rt[i]]-s[i]-'0'-sub[i])&1))?0:bin[cnt-deg[i]+cut[i]+1]);// fp(i,1,n)if(cnt-deg[i]+cut[i]+1>=1e5)puts("qwq"); sr[C]='\n',clr(); } return Ot(),0;}

转载于:https://www.cnblogs.com/bztMinamoto/p/10521260.html

你可能感兴趣的文章
搭建cdh单机版版本的hive所遇到的问题总汇
查看>>
373. Find K Pairs with Smallest Sums
查看>>
【机器学习】正则化的线性回归 —— 岭回归与Lasso回归
查看>>
javascript事件列表解说
查看>>
iotop监控磁盘动态安装
查看>>
【哲学】斯宾诺莎对于上帝是唯一的,必然存在的证明思路
查看>>
NOSQL(一)--Redis
查看>>
golang的ssh包
查看>>
请相信一个绝地反击的故事
查看>>
js select操作
查看>>
Jquery-Pager+ashx 实现分页
查看>>
网络编程
查看>>
修改xampp的mysql默认密码(转)
查看>>
AX_Unit
查看>>
软件工程个人作业02。
查看>>
一只皮球从100米的高处落地,每次落地后反弹是原高度的一半再落下,算出这只皮球在第10次落下后一共经历多少米?第10次反弹的高度是多少?...
查看>>
给20块钱买可乐,每瓶可乐3块钱,喝完之后退瓶子可以换回1块钱,问最多可以喝到多少瓶可乐...
查看>>
思维导图工具XMind
查看>>
兰顿蚂蚁
查看>>
error C2448 函数样式初始值设定项类似函数定义
查看>>