zoukankan      html  css  js  c++  java
  • 6389. 【NOIP2019模拟2019.10.26】小w学图论

    题目

    题目大意

    给你一个图,你要自己生成一个新的图,满足对于任意(x<y<z)((x,y)in E)((x,z) in E),也有((y,z) in E)
    (n)种不同的颜色给点染色,问边相连的两个点的颜色互不相同的染色方案数。


    思考历程

    几乎没有想到什么啊……
    开始时觉得这个模型比较难以转化,也没有想到什么比较好的方法。
    而且也不会求方案数。
    于是直接打了个纯暴力。
    后来打了个对拍,证明了题目给的那个伪代码中的while(1)是没有必要的。
    于是优化了一点点,然而并没有什么卵用。


    正解

    其实正解很简单。
    首先假设已经把整张图建出来了。
    (g_i)(i)连向大于(i)的点的边数。
    ((n-g_i))乘起来就是答案。
    可以从后往前考虑。对于一个点,它要和它连向的点不相同,而且它连向的点的颜色都互不相同,所以就有((n-g_i))的方案数。
    然后就是一道水题了。从前往后做,维护连出去的边。在搞完一个点之后将这个边集复制到它连向的最小的点的边集。
    很显然这是对的。
    复制的时候可以用线段树合并或启发式合并。(我居然没有想过)


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cassert>
    #define N 200010
    #define mo 998244353
    #define ll long long
    int n,m;
    struct Node{
    	Node *l,*r;
    	int num;
    } d[N*20],*null;
    int cnt;
    inline Node *newnode(){return &(d[++cnt]={null,null,0});}
    void insert(Node *&t,int l,int r,int x){
    	if (t==null)
    		t=newnode();
    	if (l==r){
    		t->num=1;
    		return;	
    	}
    	int mid=l+r>>1;
    	if (x<=mid)
    		insert(t->l,l,mid,x);
    	else
    		insert(t->r,mid+1,r,x);
    	t->num=t->l->num+t->r->num;
    }
    int find(Node *t,int l,int r){
    	if (t==null)
    		return 0;
    	if (l==r)
    		return l;
    	return t->l->num?find(t->l,l,l+r>>1):find(t->r,(l+r>>1)+1,r);
    }
    Node *merge(Node *a,Node *b,int l,int r,int x){
    	if (r<=x)
    		return null;
    	if (a==null)
    		return b;
    	if (b==null && x<l)
    		return a;
    	if (l==r){
    		a->num=1;
    		return a;
    	}
    	int mid=l+r>>1;
    //	if (mid<=x)
    //		a->l=null;
    	a->l=merge(a->l,b->l,l,mid,x);
    	a->r=merge(a->r,b->r,mid+1,r,x);
    	a->num=a->l->num+a->r->num;
    	return a;
    }
    Node *rt[N];
    int main(){
    //	freopen("in.txt","r",stdin);
    //	freopen("test.txt","w",stdout);
    	freopen("graph.in","r",stdin);
    	freopen("graph.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	null=new Node;
    	*null={null,null,0};
    	for (int i=1;i<=n;++i)
    		rt[i]=newnode();
    	for (int i=1;i<=m;++i){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		if (u>v)
    			swap(u,v);
    		insert(rt[u],1,n,v);
    	}
    	ll ans=1;
    	for (int i=1;i<=n;++i){
    //		printf("%d
    ",rt[i]->num);
    		ans=ans*(n-rt[i]->num)%mo;
    		int x=find(rt[i],1,n);
    		if (x)
    			rt[x]=merge(rt[i],rt[x],1,n,x);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    总结

    我居然连这么水的题目都没有想出来……
    我太菜了……

  • 相关阅读:
    phpexcel读取excel文件
    laravel的表单验证(下面有些信息未验证,转的)
    Laravel框架学习(Response)
    laravel文件存储Storage
    Laravel 5 教程
    js中substring和substr的用法
    jquery 规范
    总结oninput、onchange与onpropertychange事件的用法和区别
    jquery 选择器的总结
    jquery选择器中的find和空格,children和>的区别、及父节点兄弟节点,还有判断是否存在的写法
  • 原文地址:https://www.cnblogs.com/jz-597/p/11743790.html
Copyright © 2011-2022 走看看