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;
}
View Code

 

posted @ 2019-03-27 20:32  Jessiejzy  阅读(494)  评论(0编辑  收藏  举报