其他分享
首页 > 其他分享> > 「CF1661E」 Narrow Components

「CF1661E」 Narrow Components

作者:互联网

\(\texttt{「CF1661E」 Narrow Components}\)

\(\texttt{Describe}\)

给你一个 \(3\) 行 \(n\) 列的 \(01\) 矩阵 \(a\),其中 \(0\) 表示黑色格子,\(1\) 表示白色格子。
再给出 \(q\) 次讯问,每次询问给出两个整数 \(l,r\) 让你回答区间 \([l,r]\) 白色连通块的数量

\(\texttt{Input Format}\)

第 \(1\) 行给出一个整数 \(n\)。
接下来 \(3\) 行,每行有一个长度为 \(n\) 的 \(01\) 串,第 \(i\) 行 \(01\) 串的第 \(j\) 个字符表示 \(a_{i,j}\) 的值。
第 \(5\) 行给出整数 \(q\)。
接下来 \(q\) 行,每行两个整数 \(l,r\)。

\(\texttt{Output Format}\)

对于每个询问每行输出一个整数表示答案。

\(\texttt{Example In 1}\)

12
100101011101
110110010110
010001011101
8
1 12
1 1
1 2
9 9
8 11
9 12
11 12
4 6

\(\texttt{Example Out 1}\)

7
1
1
2
1
3
3
3

\(\texttt{Data}\)

\(1\le n\le 5\times 10^5,1\le q\le 3\times 10^5\\1\le l\le r\le n\)

\(\texttt{Solution1}\)

初看题目感觉信息难以维护,故考虑莫队。由与每次增加或删除都是由新加入或删除的列和当前边界决定,所以 \(\text{Add}\) 和 \(\text{Del}\) 可以简单写出。对于第 \(i\) 列,我们以第 \(3\) 行为最低位,二进制压缩成整数 \(s_i\)。由于在判断两列间的贡献比较麻烦,而且常数很大,但是每列有 \(s_i\in[0,7]\) 所以两列间仅有 \(8^2\) 种状态,可以先用程序打表 \(w_{x,y}\) 表示新加入或删除列为 \(x\),边界列为 \(y\) 的贡献,大大降低常数。下面贴出打表代码

void init()
{
	w[0][0]=0,w[0][1]=0,w[0][2]=0,w[0][3]=0,w[0][4]=0,w[0][5]=0,w[0][6]=0,w[0][7]=0;
	w[1][0]=1,w[1][1]=0,w[1][2]=1,w[1][3]=0,w[1][4]=1,w[1][5]=0,w[1][6]=1,w[1][7]=0;
	w[2][0]=1,w[2][1]=1,w[2][2]=0,w[2][3]=0,w[2][4]=1,w[2][5]=1,w[2][6]=0,w[2][7]=0;
	w[3][0]=1,w[3][1]=0,w[3][2]=0,w[3][3]=0,w[3][4]=1,w[3][5]=0,w[3][6]=0,w[3][7]=0;
	w[4][0]=1,w[4][1]=1,w[4][2]=1,w[4][3]=1,w[4][4]=0,w[4][5]=0,w[4][6]=0,w[4][7]=0;
	w[5][0]=2,w[5][1]=1,w[5][2]=2,w[5][3]=1,w[5][4]=1,w[5][5]=0,w[5][6]=1,w[5][7]=0;
	w[6][0]=1,w[6][1]=1,w[6][2]=0,w[6][3]=0,w[6][4]=0,w[6][5]=0,w[6][6]=0,w[6][7]=0;
	w[7][0]=1,w[7][1]=0,w[7][2]=0,w[7][3]=0,w[7][4]=0,w[7][5]=0,w[7][6]=0,w[7][7]=0;
}

此时考虑一个 \(\texttt{Hack}\) 数据

111
001
111

当我们新增加第 \(3\) 列(当前左边界为第 \(1\) 列)时,它不仅没有带来贡献,还把原有的两个连通块联通了,而这种情形是没有考虑到的。发现只有当前这一种特殊情形,故考虑特殊处理本情况,我们考虑向左或向右。

考虑向左,发现只有当在新加入列右方存在连续的 \(\begin{bmatrix}1\\0\\1\end{bmatrix}\) 且上下不连通时当前为 \(\begin{bmatrix}1\\1\\1\end{bmatrix}\) 才会贡献出 \(-1\),使的上下联通有且仅有 \(\begin{bmatrix}1\\1\\1\end{bmatrix}\) 一种可能性,所以记录 \(\texttt{suf}_{i}\) 表示区间 \([i,\texttt{suf}_i-1]\) 全为 \(\begin{bmatrix}1\\0\\1\end{bmatrix}\),而第 \(\texttt{suf}_i\) 列为 \(\begin{bmatrix}1\\1\\1\end{bmatrix}\),如果 \(\texttt{suf}_i=0\) 则无意义。向右显然相似。类似的,我们可以定义 \(\texttt{pre}_i\) 表示在其不为 \(0\) 的情况下表示区间 \([\texttt{pre}_i+1,i]\) 全为 \(\begin{bmatrix}1\\0\\1\end{bmatrix}\) 且第 \(\texttt{pre}_i\) 列为 \(\begin{bmatrix}1\\1\\1\end{bmatrix}\)。

我们可以根据 \(\texttt{pre},\texttt{suf}\) 在每次增减时记录是否贡献 \(-1\) 统计,至于 \(\texttt{pre},\texttt{suf}\) 则可以正序和逆序分别扫一遍 \(\mathcal O(n)\) 预处理,块长取 \(\dfrac{n}{\sqrt q}\),最终复杂度为 \(\mathcal O(n\sqrt q)\)。

\(\texttt{Solution2}\)

听说可以用并查集的奇妙做法,咕咕咕有时间补补

\(\texttt{Code}\)

点击查看代码
#include<bits/stdc++.h>
#define MOD (1000000007)
#define ll long long
#define Swap(x,y) (x^=y,y^=x,x^=y)
using namespace std;
void read(ll &x)
{
	register char ch=0;register bool f=0;x=0;
	while(ch<'0'||ch>'9'){f|=!(ch^'-');ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	x=f?-x:x;
}
void write(ll x,bool bk)
{
	if(x<0)
	{
		putchar('-');
		x=-x;
	}
	if(!x)
	{
		if(!bk) putchar('0');
		return;
	}
	write(x/10,1);
	putchar((x%10)^48);
}
void print(ll x,char ch)
{
	write(x,0);
	if(ch) putchar(ch);
}
ll w[10][10];
ll n,q,Len,L=1,R=1,cnt;
ll s[500005],idx[500005],ans[300005];
ll pre[500005],suf[500005];
struct Query{
	ll l,r,id;
}Se[300005];
bool cmp(Query a,Query b){return (idx[a.l]^idx[b.l])?(idx[a.l]<idx[b.l]):((idx[a.l]&1)?(a.r<b.r):(a.r<b.r));}
void init()
{
	w[0][0]=0,w[0][1]=0,w[0][2]=0,w[0][3]=0,w[0][4]=0,w[0][5]=0,w[0][6]=0,w[0][7]=0;
	w[1][0]=1,w[1][1]=0,w[1][2]=1,w[1][3]=0,w[1][4]=1,w[1][5]=0,w[1][6]=1,w[1][7]=0;
	w[2][0]=1,w[2][1]=1,w[2][2]=0,w[2][3]=0,w[2][4]=1,w[2][5]=1,w[2][6]=0,w[2][7]=0;
	w[3][0]=1,w[3][1]=0,w[3][2]=0,w[3][3]=0,w[3][4]=1,w[3][5]=0,w[3][6]=0,w[3][7]=0;
	w[4][0]=1,w[4][1]=1,w[4][2]=1,w[4][3]=1,w[4][4]=0,w[4][5]=0,w[4][6]=0,w[4][7]=0;
	w[5][0]=2,w[5][1]=1,w[5][2]=2,w[5][3]=1,w[5][4]=1,w[5][5]=0,w[5][6]=1,w[5][7]=0;
	w[6][0]=1,w[6][1]=1,w[6][2]=0,w[6][3]=0,w[6][4]=0,w[6][5]=0,w[6][6]=0,w[6][7]=0;
	w[7][0]=1,w[7][1]=0,w[7][2]=0,w[7][3]=0,w[7][4]=0,w[7][5]=0,w[7][6]=0,w[7][7]=0;
}
void L_Add(ll now,ll x)
{
	cnt+=w[s[x]][s[now]];
	if(((suf[now]>R)||(!suf[now]))&&(!(s[x]^7))&&(!(s[now]^5))) --cnt;//printf("[%lld,%lld]=%lld\n",x,R,cnt);
	return;
}
void L_Del(ll now,ll x)
{
	cnt-=w[s[x]][s[now]];
	if(((suf[now]>R)||(!suf[now]))&&(!(s[x]^7))&&(!(s[now]^5))) ++cnt;//printf("[%lld,%lld]=%lld\n",x,R,cnt);
	return;
}
void R_Add(ll now,ll x)
{
	cnt+=w[s[x]][s[now]];
	if((pre[now]<L)&&(!(s[x]^7))&&(!(s[now]^5))) --cnt;//printf("[%lld,%lld]=%lld\n",L,x,cnt);
	return;
}
void R_Del(ll now,ll x)
{
	cnt-=w[s[x]][s[now]];
	if((pre[now]<L)&&(!(s[x]^7))&&(!(s[now]^5))) ++cnt;//printf("[%lld,%lld]=%lld\n",L,x,cnt);
	return;
}
int main()
{
	init();
	read(n);
	Len=sqrt(n);
	for(ll i=1;i<=3;i++)
	{
		for(ll j=1;j<=n;j++)
			s[j]=(s[j]<<1)+(getchar()^48);
		getchar();
	}
	ll lst;
	lst=0;
	for(ll i=1;i<=n;i++)
		idx[i]=i/Len;
	for(ll i=1;i<=n;i++)
	{
		if((s[i]^5)&&(s[i]^7))
		{
			lst=0;
			continue;
		}
		if(!(s[i]^5)) pre[i]=lst;
		if(!(s[i]^7)) lst=i;
	}
	lst=0;
	for(ll i=n;i;i--)
	{
		if((s[i]^5)&&(s[i]^7))
		{
			lst=0;
			continue;
		}
		if(!(s[i]^5)) suf[i]=lst;
		if(!(s[i]^7)) lst=i;
	}
	read(q);
	for(ll i=1;i<=q;i++)
	{
		read(Se[i].l),read(Se[i].r);
		Se[i].id=i;
	}
	if(!(s[1]^0)) cnt=0;
	if(!(s[1]^1)) cnt=1;
	if(!(s[1]^2)) cnt=1;
	if(!(s[1]^3)) cnt=1;
	if(!(s[1]^4)) cnt=1;
	if(!(s[1]^5)) cnt=2;
	if(!(s[1]^6)) cnt=1;
	if(!(s[1]^7)) cnt=1;
	sort(Se+1,Se+q+1,cmp);
	for(ll i=1;i<=q;i++)
	{
		while(L<Se[i].l)
		{//putchar('1');
			L_Del(L+1,L);
			++L;
		}
		while(L>Se[i].l)
		{//putchar('2');
			L_Add(L,L-1);
			--L;
		}
		while(R<Se[i].r)
		{//putchar('3');
			R_Add(R,R+1);
			++R;
		}
		while(R>Se[i].r)
		{//putchar('4');
			R_Del(R-1,R);
			--R;
		}
		ans[Se[i].id]=cnt;
	}
	for(ll i=1;i<=q;i++)
		print(ans[i],'\n');
	return 0;
}

标签:CF1661E,Narrow,Components,suf,ll,texttt,le,bmatrix,now
来源: https://www.cnblogs.com/JIEGEyyds/p/16597381.html