【GDSOI2018模拟4.19】修墙

Description

w × h 是一位神仙。
众所周知,近日长城修得越来越高,across the Great Wall, reach every corner in the world也变得越来越困难。
w × h 想要分析一下某个版本墙的特征。在地图上,土地可以大致用一个无限大的黑白二维矩阵表示,其中用户为白格,墙为黑格。由于墙很高,两个用户能够互相通信当且仅当在网格上这两个白格能够只经过四联通的白格相互到达。
经过一番细致的研究,w × h发现这个地图可以由如下过程迭代构造。
地图上一开始只有一个白格。 一次迭代中,假设原来的地图为 A,那么新的地图为

其中 B 为一个与 A 边长相同且全为黑格的正方形矩阵。 例如三次迭代之后,我们得到了这样一个矩阵(W 表示白格,B 表示黑格):
这里写图片描述
经过无限次迭代之后,我们就得到了土地对应的黑白矩阵。
无限大的地图,分析起来过于困难。于是 w × h 每次会截出一个子矩阵,他想要知道这个子矩阵中的用户在墙的阻隔下组成了多少个联通块,联通块定义为极大的能够互相通信的用户集合。
由于一次询问不足以分析,w × h 需要进行 q 次询问。
q<=1e6,x1,x2<=1e9

Solution

看到wxh就知道是神仙题
首先我们把下标-1,然后我们会发现一个格子(i,j)是白的当且仅当(i&j)=0
然后所有的白格子形成一棵树,所以矩形中的白格子是森林,联通块个数用点数-边数
这里已经可以用数位Dp了,但是还是跑不过
通过归纳我们可以知道(x1,y1,x2,y2)的答案等于最左边一行的联通块个数+最上面一行的联通块个数-(x1,y1)是白格子
于是我们把问题变成了一维,然后一维又可以差分成[0,r]的问题
于是我们只需要求[0,r]中有多少个白联通块
可以发现联通块的起点满足把x末尾的0去掉之后,忽略x中为1的位置,把剩下的位置当成一个二进制数然后每次+1
这样子我们就得到了一个log的神仙做法,常数还贼小

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

int read() {
    char ch;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    int x=ch-'0';
    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x;
}

void write(int x) {
    if (!x) {puts("0");return;}
    char ch[20];int tot=0;
    for(;x;x/=10) ch[++tot]=x%10+'0';
    fd(i,tot,1) putchar(ch[i]);
    puts("");
}

int work(int x,int r) {
    if (r<0) return 0;
    for(;!(x&1);x>>=1) r>>=1;
    fd(i,29,0)
        if ((x&(1<<i))&&(r&(1<<i))) {
            r|=(1<<i)-1;
            break;
        }
    int res=0;
    fd(i,29,0) 
        if (!(x&(1<<i)))
            res=(res<<1)+((r&(1<<i))>0);
    return res+1;
}

int calc(int x,int l,int r) {
    if (!x) return 1;
    return work(x,r)-work(x,l-1)+((l>0)&&!(x&l)&&!(x&(l-1)));
}

int main() {
    freopen("wall.in","r",stdin);
    freopen("wall.out","w",stdout);
    for(int q=read();q;q--) {
        int x1=read()-1,y1=read()-1,x2=read()-1,y2=read()-1;
        write(calc(x1,y1,y2)+calc(y1,x1,x2)-!(x1&y1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/alan_cty/article/details/80019412