zoukankan      html  css  js  c++  java
  • 图 解题报告

    题意:对一个联通无向图,每次找到一个点标号(a<b<c)的三元组满足((a,b),(a,c))有边,然后连接((b,c)),直到最后找不到三元组,问最终得到的图的(n)种颜色染色方案数。


    计数问题有一个常见的思路是想办法把每个问题独立出来,考虑如何计算每个点的贡献能够独立的计算。

    注意到有一个标号的条件看起来很关键,于是我们可以想办法利用一下。

    如果先把图建出来,每个点与与它直接相连的大于它的点颜色一定不同,那么这个点的染色方案是n-与它直接相连大于它的点的个数,并且我们发现这个确实也是独立的,用乘法原理合并一下就可以了。

    然后场上没几个人找到这个结论...

    考虑我们统计的实际上是每个点向右边连的度数。

    可以按标号从小到大扫描,维护每个联通块向当前位置右边的点连边的个数,那么当前位置的答案就是它所在联通块向右边点连边的个数。

    实现的时候直接线段树启发式合并就可以了

    为了减少常数,每个点合并到它右边的最左边的点的线段树上就可以了。


    Code:

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    namespace io
    {
        const int SIZE=(1<<21)+1;
        char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];
        int f,qr;
        // getchar
        #define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
        // print the remaining part
        inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
        // putchar
        inline void putc(char x){*oS++=x;if(oS==oT)flush();}
        // input a signed integer
        template <class I>
        inline void read(I &x)
        {
            for(f=1,c=gc();c<'0'||c>'9';c=gc()) if(c=='-') f=-1;
            for(x=0;c<='9'&&c>='0';c=gc()) x=x*10+(c&15);x*=f;
        }
        // print a signed integer
        template <class I>
        inline void print(I &x)
        {
            if(!x)putc('0');if(x<0) putc('-'),x=-x;
            while(x)qu[++qr]=x%10+'0',x/=10;
            while(qr)putc(qu[qr--]);
        }
        //no need to call flush at the end manually
        struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
    }
    using io::read;
    using io::putc;
    using io::print;
    const int N=1e6+10;
    const int mod=998244353;
    int n,m,root[N],sum[N*40],ch[2][N*40],tot;
    #define ls ch[0][now]
    #define rs ch[1][now]
    void ins(int &now,int l,int r,int p)
    {
        if(!now) now=++tot;
    	if(l==r) {sum[now]=1;return;}
    	int mid=l+r>>1;
    	if(p<=mid) ins(ls,l,mid,p);
    	else ins(rs,mid+1,r,p);
    	sum[now]=sum[ls]+sum[rs];
    }
    void del(int &now,int l,int r,int p)
    {
        if(l==r) {now=0;return;}
        int mid=l+r>>1;
        if(p<=mid) del(ls,l,mid,p);
        else del(rs,mid+1,r,p);
        sum[now]=sum[ls]+sum[rs];
        if(!sum[now]) now=0;
    }
    int qryle(int now,int l,int r)
    {
    	if(l==r) return l;
    	int mid=l+r>>1;
    	if(sum[ls]) return qryle(ls,l,mid);
    	else return qryle(rs,mid+1,r);
    }
    void Merge(int &now,int v,int l,int r)
    {
    	if(!now||!v) {now=now^v;return;}
    	if(l==r) return;
    	int mid=l+r>>1;
    	Merge(ls,ch[0][v],l,mid);
    	Merge(rs,ch[1][v],mid+1,r);
    	sum[now]=sum[ls]+sum[rs];
    }
    int main()
    {
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
    	read(n),read(m);
    	for(int u,v,i=1;i<=m;i++)
    	{
    		read(u),read(v);
    		ins(root[u],1,n,v);
    	}
    	int ans=1;
    	for(int i=1;i<=n;i++)
    	{
    		ans=1ll*ans*(n-sum[root[i]])%mod;
    		if(sum[root[i]])
    		{
    		    int v=qryle(root[i],1,n);
    			Merge(root[v],root[i],1,n);
    			del(root[v],1,n,v);
    		}
    	}
    	print(ans);
    	return 0;
    }
    

    2019.3.22

  • 相关阅读:
    string与wstring之间的转换
    QTableWidget去除选中虚边框
    在新机器部署Qt+mysql程序
    Qt文件路径分隔符
    MySQL通过增加用户实现远程连接数据库
    Qt 配置文件QSettings读取以及中文问题
    git config proxy
    ubuntu14.04 us sources.list
    How to keep Environment Variables when Using SUDO
    ubuntu hash sum mismatch error
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10579399.html
Copyright © 2011-2022 走看看