一、题目
点此看题
题目描述
有
n
n
n层楼,每层有两个门(编号为
1
/
2
1/2
1/2),
i
i
i层到
i
+
1
i+1
i+1的门两两相通,有下列操作:
- 把 i i i层到 i + 1 i+1 i+1层的 x , y x,y x,y两个门的状态改变(联通变成不同,不同变成联通)
- 询问 x x x到 y y y的方案数,可以从 x x x任意门入, y y y任意门出。
数据范围
多组数据,
1
≤
n
,
m
≤
50000
1\leq n,m\leq 50000
1≤n,m≤50000
二、解法
考虑
d
p
[
i
]
[
0
/
1
]
dp[i][0/1]
dp[i][0/1]也就是到了
i
i
i层的
1
/
2
1/2
1/2号门的方案数,
p
d
[
i
]
[
j
]
pd[i][j]
pd[i][j]表示
i
,
j
i,j
i,j号门之间有无通路,有下列转移:
d
p
[
i
]
[
0
]
=
p
d
[
0
]
[
0
]
×
d
p
[
i
−
1
]
[
0
]
+
p
d
[
1
]
[
0
]
×
d
p
[
i
−
1
]
[
1
]
dp[i][0]=pd[0][0]\times dp[i-1][0]+pd[1][0]\times dp[i-1][1]
dp[i][0]=pd[0][0]×dp[i−1][0]+pd[1][0]×dp[i−1][1]
d
p
[
i
]
[
1
]
=
p
d
[
0
]
[
1
]
+
d
p
[
i
−
1
]
[
0
]
+
p
d
[
1
]
[
1
]
×
d
p
[
i
−
1
]
[
1
]
dp[i][1]=pd[0][1]+dp[i-1][0]+pd[1][1]\times dp[i-1][1]
dp[i][1]=pd[0][1]+dp[i−1][0]+pd[1][1]×dp[i−1][1]上述转移很像矩阵乘法的递推,我们可以把
[
x
,
y
−
1
]
[x,y-1]
[x,y−1]之间的矩阵乘起来,然后对系数求和就是方案数。
然后发现可以用线段树优化,第一个操作就是一个单点修改,第二个操作就是一个区间查询,时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define LL long long
const LL MOD = 1e9+7;
const LL MAXN = 100005;
LL read()
{
LL x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m;LL x,y;
struct Matrix
{
LL a[3][3];
Matrix() {memset(a,0,sizeof a);}
Matrix operator * (const Matrix &B)
{
Matrix R;
for(LL i=1;i<=2;i++)
for(LL j=1;j<=2;j++)
for(LL k=1;k<=2;k++)
R.a[i][k]=(R.a[i][k]+a[i][j]*B.a[j][k])%MOD;
return R;
}
}I,tr[MAXN*4];
void build(LL i,LL l,LL r)
{
if(l==r)
{
tr[i].a[1][1]=tr[i].a[1][2]=tr[i].a[2][1]=tr[i].a[2][2]=1;
return ;
}
LL mid=(l+r)/2;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
tr[i]=tr[i<<1]*tr[i<<1|1];
}
void updata(LL i,LL l,LL r,LL id)
{
if(l==r)
{
tr[i].a[x][y]^=1;
return ;
}
LL mid=(l+r)/2;
if(mid>=id)
updata(i<<1,l,mid,id);
else
updata(i<<1|1,mid+1,r,id);
tr[i]=tr[i<<1]*tr[i<<1|1];
}
Matrix query(LL i,LL l,LL r)
{
if(x>r || l>y || l>r) return I;
if(x<=l && r<=y) return tr[i];
LL mid=(l+r)/2;
Matrix res=query(i<<1,l,mid);
return res*query(i<<1|1,mid+1,r);
}
signed main()
{
//freopen("fuck.in","r",stdin);
//freopen("mine.out","w",stdout);
I.a[1][1]=I.a[2][2]=1;
while(scanf("%d %d",&n,&m)!=EOF)
{
n--;
build(1,1,n);
while(m--)
{
LL op=read();
if(op==1)
{
LL p=read();x=read();y=read();
updata(1,1,n,p);
}
else
{
x=read();y=read();
if(x>y) swap(x,y);
y--;
Matrix t=query(1,1,n);
printf("%lld\n",(t.a[1][1]+t.a[1][2]+t.a[2][1]+t.a[2][2])%MOD);
}
}
}
}