zoukankan      html  css  js  c++  java
  • [SCOI2016] 萌萌哒

    一、题目

    点此看题

    二、解法

    首先拆限制,看似他给的是区间相等,其实是若干组单点相等。

    那么把单点的限制用并查集连起来,我们只需要关系联通块个数即可。

    问题转化为了每次给两个区间,要求区间对应位连边。线段树优化建图做不了,但是 (st) 表可以,设 (fa[i][j]) 表示以 (i) 为左端点,长度为 (2^j) 区间的并查集,我们把这个看成节点,但他的作用实际上是打标记

    初始化 (fa[i][..]=i),打标记时直接把标记节点的并查集连起来,最后还需要下传一次,对于点 ((i,j)),我们找到他在并查集上的父亲 ((x,j)),然后把 ((i,j-1),(x,j-1))((i+2^{j-1},j-1),(x+2^{j-1},j-1)) 分别连起来即可。

    三、总结

    (st) 表对位优化建图可以当做一个小套路记下来,但是倍增是真的强,在区间问题中我们要主动使用它。

    #include <cstdio>
    const int M = 100005;
    const int MOD = 1e9+7;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,ans,fa[M][20];
    int find(int x,int y)
    {
    	if(fa[x][y]!=x) fa[x][y]=find(fa[x][y],y);
    	return fa[x][y];
    }
    void merge(int x,int y,int k)
    {
    	int u=find(x,k),v=find(y,k);
    	fa[u][k]=v;
    }
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    		for(int j=0;j<=19;j++)
    			fa[i][j]=i;
    	for(int i=1;i<=m;i++)
    	{
    		int l1=read(),r1=read(),l2=read(),r2=read();
    		for(int j=19;j>=0;j--)
    			if(l1+(1<<j)-1<=r1)
    			{
    				merge(l1,l2,j);
    				l1+=(1<<j);l2+=(1<<j);
    			}
    	}
    	for(int j=19;j>=1;j--)
    		for(int i=1;i+(1<<j)-1<=n;i++)
    		{
    			int x=find(i,j);
    			merge(i,x,j-1);
    			merge(i+(1<<j-1),x+(1<<j-1),j-1);
    		}
    	for(int i=1;i<=n;i++)
    		if(fa[i][0]==i)
    			ans=!ans?9:(ans*10ll%MOD);
    	printf("%d
    ",ans);
    }
    
  • 相关阅读:
    Centos7搭建OpenNebula云平台
    Python中__new__和__init__的区别与联系
    16个python常用魔法函数
    微信小程序< 1 > ~ Hello 微信小程序
    扬帆起航,再踏征程(一)
    Java 社区平台
    Java 社区平台
    <Android 应用 之路> 一个类似今日头条的APP
    使用标准C读取文件遇到的结构体对齐问题及其解决办法
    编译64位cu文件的设置
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15017835.html
Copyright © 2011-2022 走看看