ZOJ 2671 (线段树+矩阵乘法)

这题着实是锻炼线段树的一个好题,纯模板题但是加上了一点其他的东西,细节很多

细节一:格式错误,每两个一大组数据和之间需要有有一个换行。

细节二:每两个输出之间有一个换行

细节三:每次需要清空存储矩阵的结构体(但是我不是特别明白为什么要清空)

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <stack>
#include <cmath>
#define fuck() (cout << "--------------------------------" << endl)
#define MOD 1000000007
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 30000 + 10;
int mod,m,n;
struct matrix
{
    long long  a[2][2];
    matrix()
    {
        a[0][0] = a[1][1] = 0;
        a[1][0] = a[0][1] = 0;
    }
    void read()
    {
        for(int i=0; i<2; i++)
            for(int j=0; j<2; j++)
                scanf("%lld",&a[i][j]);
    }
    matrix operator * (const matrix &p) const
    {
        matrix x;
        for(int i=0; i<2; i++)
            for(int j=0; j<2; j++)
                for(int k=0; k<2; k++)
                {
                    x.a[j][k] += (a[j][i] * p.a[i][k] ) % mod;
                    x.a[j][k] %= mod;
                }
        return x;
    }
};
matrix node[maxn],sum[maxn*4];
void build(int o, int l, int r)
{
    if(l == r)
    {
        sum[o] = node[l];
        return;
    }
    int m = (l+r)/2;
    build(o*2, l, m);
    build(o*2+1, m+1, r);
    sum[o] = sum[o*2] * sum[o*2+1];
}
matrix query(int o, int l, int r, int ql, int qr)
{
    if(ql <= l && qr >= r)
    {
        return sum[o];
    }
    int m = (l+r)/2;
    matrix x;
    x.a[1][1] = x.a[0][0] = 1;
    x.a[1][0] = x.a[0][1] = 0;
    if(ql <= m) x = x * query(2*o, l, m, ql, qr);
    if(qr > m) x = x * query(2*o+1, m+1, r, ql, qr);
    return x;


}
int main()
{
    bool flag = true;
    while(scanf("%d%d%d",&mod,&n,&m) == 3)
    {
        if(!flag) printf("\n");
        flag = false;
        for(int i=1; i<=n; i++)
            node[i].read();
        build(1,1,n);
        for(int k=0; k<m; k++)
        {
             int ll,rr;
             scanf("%d%d",&ll,&rr);
             matrix ans =  query(1,1,n,ll,rr);
             if(k) printf("\n");
             for(int i=0; i<2; i++)
             {
                 for(int j=0; j<2; j++)
                 {
                     if(!j) printf("%lld",ans.a[i][j]);
                     else printf(" %lld\n",ans.a[i][j]);
                 }
             }
        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值