dtoj#4299. 圖(graph)

題目描述:

對於一個無向圖 $G$,三元組 $(a, b, c)$ 被稱爲優秀的當且僅當知足以下條件:node

$1. a < b < c$;c++

$2. a $ 與 $b$ 有邊相連;git

$3. a $ 與 $c$ 有邊相連;算法

$4. b$ 與 $c$ 沒有邊相連。ide

如今有一個 $n$ 個點的連通無向圖 $G$,每次找一個優秀的三元組 $(a, b, c)$ 將 $b$ 和 $c$ 連邊,若是沒有則結束加邊過程。spa

問最終獲得的圖有多少種用 $n$ 種顏色對點染色的方案,對 $998244353$ 取模後輸出。code

一種染色方案合法當且僅當每一個點顏色是 $1$ 到 $n$ 中的一個,而且一條邊兩端的點顏色不一樣。blog

算法標籤:線段樹合併

思路:

對於一個無向圖 $G$,三元組 $(a, b, c)$ 被稱爲優秀的當且僅當知足以下條件:get

$1. a < b < c$;it

$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
相關文章
相關標籤/搜索