ZOJ_2671_Cryptography_线段树

昨天搞数模,每个题都跟打ACM一样。。


题意:

给一个长为n的2*2方阵的一维数组,询问m次,每次给出l,r,询问矩阵从第l个乘到第r个的积是多少



Input

There are several test cases in the input. The first line of each case contains r ( 1 <= r <= 10,000), n ( 1 <= n <= 30,000) and m ( 1 <= m <= 30,000). Next n blocks of two lines, containing two integer numbers ranging from 0 to r - 1 each, describe matrices. Blocks are separated with blank lines. They are followed by m pairs of integer numbers ranging from 1 to n each that describe segments, products for which are to be calculated.
There is an empty line between cases.

Output

Print m blocks containing two lines each. Each line should contain two integer numbers ranging from 0 to r - 1 and define the corresponding product matrix.
There should be an empty line between cases.

Separate blocks with an empty line.

裸的线段树,利用的核心是二分算法。现在数据结构用OO写挺不下来怎么办


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
using namespace std;
#define mxn 30010
int r,n,m;
class matrix{
private:
	int a[2][2];
public:
	matrix(){}
	matrix(int m,int n,int p,int q){
		a[0][0]=m,a[0][1]=n;
		a[1][0]=p,a[1][1]=q;
	}
	void read(){
		scanf("%d%d%d%d",&a[0][0],&a[0][1],&a[1][0],&a[1][1]);
	}
	void print(){
		printf("%d %d\n%d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]);
	}
	matrix operator * (const matrix& in)const{
		matrix ret;
		for(int i=0;i<2;++i)
			for(int j=0;j<2;++j)
				ret.a[i][j]=(a[i][0]*in.a[0][j]%r+a[i][1]*in.a[1][j]%r)%r;
		return ret;
	}
}M[mxn];
class node{
public:
	int ll,rr;
	matrix pro;
};
class segment_tree{
private:
	node nd[mxn<<2];
	void merge(int id){
		int ls=id<<1,rs=ls|1;
		nd[id].pro=nd[ls].pro*nd[rs].pro;
	}
public:
	void build(int l,int r,int id){
		nd[id].ll=l;
		nd[id].rr=r;
		if(l==r){
			nd[id].pro=M[l];
			return;
		}
		int m=(l+r)>>1,ls=id<<1,rs=ls|1;
		build(l,m,ls);
		build(m+1,r,rs);
		merge(id);
	}
	matrix find(int l,int r,int id){
		if(l==nd[id].ll&&r==nd[id].rr)
			return nd[id].pro;
		int m=(nd[id].ll+nd[id].rr)>>1,ls=id<<1,rs=ls|1;
		if(r<=m)	return find(l,r,ls);
		else if(l>m)	return find(l,r,rs);
		else	return find(l,m,ls)*find(m+1,r,rs);
	}
}Tree;
int main(){
	bool first=true;
	while(scanf("%d%d%d",&r,&n,&m)!=EOF){
		if(!first)	puts("");
		first=false;
		for(int i=0;i<n;++i)	M[i].read();
		Tree.build(0,n-1,1);
		int l,r;
		matrix ans;
		for(int i=0;i<m;++i){
			scanf("%d%d",&l,&r);
			ans=Tree.find(l-1,r-1,1);
			ans.print();
			if(i!=m-1)	puts("");
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值