zoukankan      html  css  js  c++  java
  • Bzoj_5287 [Hnoi2018]毒瘤

    题意
    给你一个图,求这个图的独立点集(集合内点互不相邻)个数。
    (n leqslant 10^5,n-1 leqslant m leqslant n+10)

    题解
    对于m=n-1的情况,直接上Tree_Dp即可,(f_{u,1}=prod (f_{v,0}+f_{v,1}),f_{u,0}=prod f_{v,1})
    然后我们发现m-n是个很小的数字,我们考虑可以先建出一个生成树,再考虑那么非树边。
    非树边最多11条,我们可以直接枚举非树边两端点选或不选(实际上可以只枚举一端)。然后在树上直接Dp,复杂度(O(2^{m-n+1}n))然后你就有75分了

    尝试对这个算法进行优化。我们发现每次Dp都有很多重复的步骤(比如完全没有建在虚树里的子树),我们可以提前预处理。但是在虚树边上的点我们还是得一个一个枚举。但是我们又发现,对于每一个虚树边<u,v>,(f_{v,1})(f_{u,0})的贡献只需要乘上一个固定的系数。具体来说,对于某个虚树边<u,v>,我们设(f_{v,1}=x),那么点v在原树上暴力向上跳,并将周围的子树的贡献也乘进去,最终对(f_{u,0})的贡献一定是乘上(k_{<u,v>,0,1} cdot x)。所以我们对于每一个虚树边<u,v>以及u,v选或不选的每一种状态都预处理里出这个系数,然后枚举状态并在虚树上Dp,这样复杂度便是(O(n+s imes 2^s))(s为非树边两端点的点集大小)。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=1e5;
    const int mod=998244353;
    int n,m,tot,cnt,Time,k;
    int a[maxn+8],b[maxn+8],fa[maxn+8];
    int pre[maxn*2+8],now[maxn+8],son[maxn*2+8];
    int jump[maxn*2+8][28],dfn[maxn+8],dep[maxn+8];
    int tmp[2],g[maxn+8][2],res[maxn+8][2],val[maxn*2+8][2][2];
    int st[maxn+8];
    int f[maxn+8][2];
    bool vis[maxn+8];
    
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    	return x*f;
    }
    
    struct Disjoint_Set_Union
    {
    	int fa[maxn+8];
    	int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    }DSU;
    
    void add(int u,int v)
    {
    	pre[++tot]=now[u];
    	now[u]=tot;
    	son[tot]=v;
    }
    
    void dfs(int x)
    {
    	jump[dfn[x]=++Time][0]=x;
    	dep[x]=dep[fa[x]]+1;
    	for (int p=now[x];p;p=pre[p])
    		{
    			int child=son[p];
    			if (child==fa[x]) continue;
    			fa[child]=x;
    			dfs(child);
    			jump[++Time][0]=x;
    		}
    }
    
    int RMQ(int x,int y){return dep[x]<dep[y]?x:y;}
    
    void Build_St()
    {
    	for (int j=1;j<=log(Time)/log(2);j++)
    		for (int i=1;i<=Time-(1<<j)+1;i++)
    			jump[i][j]=RMQ(jump[i][j-1],jump[i+(1<<(j-1))][j-1]);
    }
    
    bool cmp(int x,int y){return dfn[x]<dfn[y];}
    
    int Get_Lca(int x,int y)
    {
    	if (dfn[x]>dfn[y]) swap(x,y);
    	int len=dfn[y]-dfn[x]+1,t=log(len)/log(2);
    	return RMQ(jump[dfn[x]][t],jump[dfn[y]-(1<<t)+1][t]);
    }
    
    void Make_F(int x,int fa)
    {
    	f[x][0]=1,f[x][1]=1;
    	for (int p=now[x];p;p=pre[p])
    		{
    			int child=son[p];
    			if (child==fa) continue;
    			Make_F(child,x);
    			f[x][1]=1ll*f[x][1]*f[child][0]%mod;
    			f[x][0]=1ll*(f[child][1]+f[child][0])%mod*f[x][0]%mod;
    		}
    }
    
    int update(int x,int y,int i,int j)
    {
    	tmp[i^1]=0,tmp[i]=1;
    	while(x!=y)
    		{
    			vis[x]=1;
    			for (int p=now[x];p;p=pre[p])
    				{
    					int child=son[p];
    					if (vis[child]||child==fa[x]) continue;
    					tmp[0]=1ll*(f[child][0]+f[child][1])%mod*tmp[0]%mod;
    					tmp[1]=1ll*tmp[1]*f[child][0]%mod;
    				}
    			swap(tmp[0],tmp[1]);
    			tmp[0]=(tmp[0]+tmp[1])%mod;
    			x=fa[x];
    		}
    	return tmp[j];
    }
    
    void Get_Res(int x)
    {
    	res[x][0]=1,res[x][1]=1;
    	for (int p=now[x];p;p=pre[p])
    		{
    			int child=son[p];
    			if (vis[child]||child==fa[x]) continue;
    			vis[child]=1;
    			res[x][0]=1ll*(f[child][0]+f[child][1])%mod*res[x][0]%mod;
    			res[x][1]=1ll*res[x][1]*f[child][0]%mod;
    		}
    }
    
    struct Virtual_Tree
    {
    	int tot;
    	int color[maxn+8];
    	int pre[maxn*2+8],now[maxn+8],son[maxn*2+8];
    	void add(int u,int v)
    	{
    		pre[++tot]=now[u];
    		now[u]=tot;
    		son[tot]=v;
    	}
    	void insert(int u,int v){add(u,v),add(v,u);}
    	void Make_Val(int x,int fa)
    	{
    		for (int p=now[x];p;p=pre[p])
    			{
    				int child=son[p];
    				if (child==fa) continue;
    				Make_Val(child,x);
    				for (int i=0;i<2;i++)
    					for (int j=0;j<2;j++)
    							val[p][i][j]=update(child,x,i,j);
    			}
    		Get_Res(x);
    	}
    	void calc(int x,int fa)
    	{
    		if (color[x]==-1) g[x][0]=res[x][0],g[x][1]=res[x][1];
    		else g[x][color[x]]=res[x][color[x]],g[x][color[x]^1]=0;
    		for (int p=now[x];p;p=pre[p])
    			{
    				int child=son[p];
    				if (child==fa) continue;
    				calc(child,x);
    				for (int i=0;i<2;i++)
    					g[x][i]=1ll*(1ll*g[child][0]*val[p][0][i]%mod+1ll*g[child][1]*val[p][1][i]%mod)*g[x][i]%mod;
    			}
    	}
    	void solve()
    	{
    		int ans=0;
    		Make_Val(n,0);
    		memset(color,-1,sizeof(color));
    		for (int sta=0;sta<1<<k;sta++)
    			{
    				for (int i=1;i<=k;i++) color[a[i]]=1&(sta>>(i-1));
    				bool flag=0;
    				for (int i=1;i<=cnt;i+=2)
    					if (color[b[i]]&color[b[i+1]])
    						{
    							flag=1;
    							break;
    						}
    				if (flag) continue;
    				calc(n,0);
    				ans=(ans+g[n][0])%mod;
    			}
    		printf("%d
    ",ans);
    	}
    }VT;
    
    void solve()
    {
    	sort(a+1,a+cnt+1,cmp);
    	k=unique(a+1,a+cnt+1)-a-1;
    	int tail=1;
    	st[tail]=n;
    	for (int i=1;i<=k;i++)
    		{
    			int Lca=Get_Lca(a[i],st[tail]),pre=0;
    			while(dep[Lca]<dep[st[tail]])
    				{
    					if (pre) VT.insert(pre,st[tail]);
    					pre=st[tail--];
    				}
    			if (pre) VT.insert(pre,Lca);
    			if (Lca!=st[tail]) st[++tail]=Lca;
    			st[++tail]=a[i];
    		}
    	tail--;
    	while(tail) VT.insert(st[tail],st[tail+1]),tail--;
    	VT.solve();
    }
    
    int main()
    {
    	n=read(),m=read();
    	for (int i=1;i<=n;i++) DSU.fa[i]=i;
    	for (int i=1;i<=m;i++)
    		{
    			int u=read(),v=read();
    			if (DSU.find(u)!=DSU.find(v))
    				{
    					add(u,v),add(v,u);
    					DSU.fa[DSU.find(u)]=DSU.find(v);
    				}
    			else
    				{
    					b[cnt+1]=u,b[cnt+2]=v;
    					a[++cnt]=u,a[++cnt]=v;
    				}
    		}
    	++n;
    	add(1,n),add(n,1);
    	dfs(n);
    	Build_St();
    	Make_F(n,0);
    	solve();
    	return 0;
    }
    
    
  • 相关阅读:
    事务管理思考
    sleep、yield、wait的区别
    线程异常
    线程
    JAVA线程中断
    volatile synchronized在线程安全上的区别
    jms amqp activemq rabbitmq的区别
    servlet不是线程安全的
    雪花算法
    个人税收申报时候对于“全年一次性奖金“的处理
  • 原文地址:https://www.cnblogs.com/Alseo_Roplyer/p/10243556.html
Copyright © 2011-2022 走看看