dtoj#4299. 图(graph)
题目描述:
对于一个无向图 $G$,三元组 $(a, b, c)$ 被称为优秀的当且仅当满足如下条件:
$1. a < b < c$;
$2. a $ 与 $b$ 有边相连;
$3. a $ 与 $c$ 有边相连;
$4. b$ 与 $c$ 没有边相连。
现在有一个 $n$ 个点的连通无向图 $G$,每次找一个优秀的三元组 $(a, b, c)$ 将 $b$ 和 $c$ 连边,如果没有则结束加边过程。
问最终得到的图有多少种用 $n$ 种颜色对点染色的方案,对 $998244353$ 取模后输出。
一种染色方案合法当且仅当每个点颜色是 $1$ 到 $n$ 中的一个,并且一条边两端的点颜色不同。
算法标签:线段树合并
思路:
对于一个无向图 $G$,三元组 $(a, b, c)$ 被称为优秀的当且仅当满足如下条件:
$1. a < b < c$;
$2. a $ 与 $b$ 有边相连;
$3. a $ 与 $c$ 有边相连;
$4. b$ 与 $c$ 没有边相连。
现在有一个 $n$ 个点的连通无向图 $G$,每次找一个优秀的三元组 $(a, b, c)$ 将 $b$ 和 $c$ 连边,如果没有则结束加边过程。
问最终得到的图有多少种用 $n$ 种颜色对点染色的方案,对 $998244353$ 取模后输出。
一种染色方案合法当且仅当每个点颜色是 $1$ 到 $n$ 中的一个,并且一条边两端的点颜色不同。
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1e6+5,p=998244353; int n,m,rt[N],fa[N],cnt,tot,head[N],ne[N<<1],to[N<<1],ans=1; struct node{ int x,l,r,num; }t[N*21]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il void ins(int x,int y){ ne[++tot]=head[x]; head[x]=tot;to[tot]=y; } il int getfa(int x){ return fa[x]?(fa[x]=getfa(fa[x])):x; } il void update(int x){ t[x].num=t[t[x].l].num+t[t[x].r].num; } il void insert(int &x,int l,int r,int pos){ if(!x)x=++cnt; if(l==r){t[x].num=1;return;} int mid=(l+r)>>1; if(pos<=mid)insert(t[x].l,l,mid,pos); else insert(t[x].r,mid+1,r,pos); update(x); } il void merge(int &x,int y,int l,int r){ if(!x||!y){x=x+y;return;} if(l==r){t[x].num=1;return;} int mid=(l+r)>>1; merge(t[x].l,t[y].l,l,mid); merge(t[x].r,t[y].r,mid+1,r); update(x); } il int query(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr)return t[x].num; int mid=(l+r)>>1;int res=0; if(ql<=mid)res=query(t[x].l,l,mid,ql,qr); if(mid<qr)res+=query(t[x].r,mid+1,r,ql,qr); return res; } int main() { n=read();m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); ins(x,y);ins(y,x); insert(rt[min(x,y)],1,n,max(x,y)); } for(int i=1;i<=n;i++){ int f1=getfa(i); for(int j=head[i];j;j=ne[j]){ int f2=getfa(to[j]); if(to[j]<i&&(f2^f1))merge(rt[f1],rt[f2],1,n),fa[f2]=f1; } ans=1ll*ans*(n-query(rt[f1],1,n,i+1,n))%p; } printf("%d\n",ans); return 0; }