链接:http://acm.hdu.edu.cn/showproblem.php?pid=5068
根据每层两个点的到下一层两个点的连接情况,可以得到一个2*2的矩阵,初始矩阵全部联通都为1,不连通为0,显然一段区间内的方案数就是区间内矩阵相乘后的矩阵行列值求和。简单的线段树维护区间矩阵乘积就好。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
#include <string>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 50005
#define MAXM 4500000
const long long mod=1000000007;
struct Mat
{
long long a[2][2];
}mat[MAXN<<2];
Mat Mul(Mat x, Mat y)
{
Mat ne;
for(int i=0; i<2; ++i)
for(int j=0; j<2; ++j)
{
ne.a[i][j]=0;
for(int k=0; k<2; ++k)
ne.a[i][j]=(ne.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
}
return ne;
}
void build(int poi, int x, int y)
{
if(x==y)
{
for(int i=0; i<2; ++i)for(int j=0; j<2; ++j)
mat[poi].a[i][j]=1;
return ;
}
int mid=(x+y)>>1;
build(poi<<1,x,mid);
build(poi<<1^1,mid+1,y);
mat[poi]=Mul(mat[poi<<1], mat[poi<<1^1]);
}
Mat query(int poi, int l, int r, int x, int y)
{
if(l>=x&&r<=y)
{
return mat[poi];
}
int mid=(l+r)>>1;
if(mid>=y)return query(poi<<1,l,mid,x,y);
if(mid<x)return query(poi<<1^1,mid+1,r,x,y);
return Mul(query(poi<<1,l,mid,x,y),query(poi<<1^1,mid+1,r,x,y));
}
void change(int poi, int x, int y, int A, int B, int temp)
{
if(x==y)
{
mat[poi].a[A][B]^=1;
return ;
}
int mid=(x+y)>>1;
if(temp<=mid)change(poi<<1,x,mid,A,B,temp);
else change(poi<<1^1,mid+1,y,A,B,temp);
mat[poi]=Mul(mat[poi<<1], mat[poi<<1^1]);
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
build(1,1,n);
int p,x,y,z;
for(int i=0; i<m; ++i)
{
scanf("%d",&p);
if(p)
{
scanf("%d%d%d",&x,&y,&z);
change(1,1,n,y-1,z-1,x);
}
else
{
scanf("%d%d",&x,&y);
Mat temp=query(1,1,n,x,y-1);
long long ans=0;
for(int i=0; i<2; ++i)
for(int j=0; j<2; ++j)
ans=(ans+temp.a[i][j])%mod;
printf("%I64d\n",ans);
}
}
}
return 0;
}
/*
5
2 5
*/