/*
*Rainto96
*Beijing University of Posts and Telecommunications School of Software Engineering
*http://blog.csdn.net/u011775691
http://www.bnuoj.com/v3/problem_show.php?pid=24253
n个数,m个操作
1.查询区间积
2.区间中每个数乘x
3.区间中每个数除x
坑:
1.将一个数分解成M的相关质数×某数时候,注意该数为0的情况
2. 0可以除以任何数,然后M质数频数表项可能为负数,小心qPow会停不下来。可以处理为,qPow(a,n)发现n<0则return 0,因为接下来的操作中,0位肯定还是0不会变
*/
#include <ctime>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <climits>
#include <cassert>
using namespace std;
#define pb push_back
#define ALL(x) x.begin(),x.end()
#define VINT vector<int>
#define PII pair<int,int>
#define MP(x,y) make_pair((x),(y))
#define ll long long
#define ull unsigned ll
#define MEM0(x) memset(x,0,sizeof(x))
#define MEM(x,val) memset((x),val,sizeof(x))
#define scan(x) scanf("%d",&(x))
#define scan2(x,y) scanf("%d%d",&(x),&(y))
#define scan3(x,y,z) scanf("%d%d%d",&(x),&(y),&(z))
#define scan4(x,y,z,k) scanf("%d%d%d%d",&(x),&(y),&(z),&(k))
#define Max(a,b) a=max(a,b)
#define Min(a,b) a=min(a,b)
using namespace std;
//******************************
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
if(a==0&&b==0) return -1;//无最大公约数
if(b==0){x=1;y=0;return a;}
long long d=extend_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
long long mod_reverse(long long a,long long n)
{
long long x,y;
long long d=extend_gcd(a,n,x,y);
if(d==1) return (x%n+n)%n;
else return -1;
}
const long long UP=66666;
int prm[UP+10];
bool visP[UP+10];
int pn;
void getPrm(){
for(int i=2;i<=UP;i++){
if(!visP[i]){
prm[pn++]=i;
for(int j=i;j<=UP;j+=i) visP[j]=true;
}
}
}
//--------------------------------------------------------------------
int n,M;
const int MAXN = 10111;
int f[MAXN];
int Mprm[66];
int CNT=0;
int qPow(int a,int n){
//cerr<<a<<" "<<n<<endl;
//n=abs(n);
//assert(n>=0);
int sum=1;
int now=a;
while(n){
if(n&1) sum=1LL*sum*now%M;
now=1LL*now*now%M;
n>>=1;
}
return sum;
}
int qPow2(int a,int n){
//cerr<<a<<" "<<n<<endl;
//n=abs(n);
if(n<0) return 0;
//assert(n>=0);
int sum=1;
int now=a;
while(n){
if(n&1) sum=1LL*sum*now%M;
now=1LL*now*now%M;
n>>=1;
}
return sum;
}
struct Vector{
int v[10];
Vector(){
memset(v,0,sizeof(v));
}
Vector operator + (const Vector& s){
Vector tt = *this;
for(int i=0;i<CNT;i++) {
tt.v[i] += s.v[i];
//assert(tt.v[i] >= 0);
}
return tt;
}
Vector operator * (const int num){
Vector tt = *this;
for(int i=0;i<CNT;i++) tt.v[i] *= num;
return tt;
}
int getValue(){
int val = 1;
for(int i=0;i<CNT;i++) val = 1LL * val * qPow2(Mprm[i] , v[i]) % M;
return val;
}
void clear(){
for(int i=0;i<CNT;i++) v[i] = 0;
}
void fu(){
for(int i=0;i<CNT;i++) v[i] = -v[i];
}
void print(){
for(int i=0;i<CNT;i++) printf("%d " , v[i]);
cout<<endl;
}
};
void makeMprm(){
CNT=0;
int tmp=M;
for(int i=0;i<pn && prm[i] * prm[i] <= tmp;i++){
if(tmp%prm[i] == 0){
Mprm[CNT++] = prm[i];
while( tmp%prm[i] == 0 ){
tmp /= prm[i];
}
}
}
if(tmp!=1) Mprm[CNT++] = tmp;
}
#define PIV pair<int ,Vector >
pair<int ,Vector > trans(int x){
//cerr<<"In trans:"<<x;
Vector vec;
for(int i=0;i<CNT;i++){
while(x!=0 && x % Mprm[i] == 0) {
x/= Mprm[i];
vec.v[i] ++;
}
}
//cerr<<" -> "<<x<<" ";
//vec.print();
return MP(x,vec);
}
#define lson(x) (x)<<1
#define rson(x) (x)<<1|1
struct Node {
int l, r , val ,len;
Vector V;
bool lazy;
int lazyval;
Vector lazyV;
};
struct Seg{
Node node[MAXN * 6];
void pushup(int x) {
node[x].V = node[lson(x)].V + node[rson(x)].V;
node[x].val = 1LL * node[lson(x)].val * node[rson(x)].val % M;
}
void pushdown(int x) {
if (node[x].lazy) {
node[lson(x)].lazyV =node[lson(x)].lazyV + node[x].lazyV;
node[lson(x)].V =node[lson(x)].V + node[x].lazyV * node[lson(x)].len;
node[rson(x)].lazyV =node[rson(x)].lazyV + node[x].lazyV;
node[rson(x)].V =node[rson(x)].V + node[x].lazyV * node[rson(x)].len;
node[lson(x)].lazyval =1LL * node[lson(x)].lazyval * node[x].lazyval % M;
node[lson(x)].val =1LL * node[lson(x)].val * qPow(node[x].lazyval , node[lson(x)].len) % M;
node[rson(x)].lazyval =1LL * node[rson(x)].lazyval * node[x].lazyval % M;
node[rson(x)].val =1LL * node[rson(x)].val * qPow(node[x].lazyval , node[rson(x)].len) % M;
node[lson(x)].lazy = true;
node[rson(x)].lazy = true;
node[x].lazy = false;
node[x].lazyval=1;
node[x].lazyV.clear();
}
}
void build(int l, int r, int x = 1) {
node[x].l = l; node[x].r = r; node[x].lazy = false;
node[x].V.clear();
node[x].lazyV.clear(); node[x].lazyval=1; node[x].len = r-l+1;
if (l == r) {
PIV p = trans(f[l]);
node[x].val = p.first % M;
node[x].V = p.second;
return;
}
int mid = (l + r) / 2;
build(l, mid, lson(x));
build(mid + 1, r, rson(x));
pushup(x);
}
void update(int l, int r,PIV& piv , int x = 1) {
if (node[x].l >= l && node[x].r <= r) {
node[x].lazy = true;
node[x].lazyV = node[x].lazyV + piv.second;
node[x].V = node[x].V + piv.second * node[x].len;
node[x].val = 1LL * node[x].val *qPow(piv.first,node[x].len) % M;
node[x].lazyval = 1LL * node[x].lazyval * piv.first % M;
return;
}
int mid = (node[x].l + node[x].r) / 2;
pushdown(x);
if (l <= mid) update(l, r,piv, lson(x));
if (r > mid) update(l, r,piv, rson(x));
pushup(x);
}
int query(int l, int r, int x = 1) {
if (node[x].l >= l && node[x].r <= r) {
return 1LL * node[x].val * node[x].V.getValue() % M;
}
int mid = (node[x].l + node[x].r) / 2;
pushdown(x);
int ans = 1;
if (l <= mid) ans = 1LL * ans * query(l, r, lson(x)) % M;
if (r > mid) ans = 1LL * ans * query(l, r, rson(x)) % M;
pushup(x);
return ans;
}
void print(int l,int r,int x=1){
cerr<<"point:"<<x<<endl;
cerr<<"l:"<<node[x].l <<"r:"<<node[x].r<<endl;
cerr<<"val:"<<node[x].val<<endl;
cerr<<"TrueVal:"<<node[x].val * node[x].V.getValue() %M<<endl;
cerr<<"V:";node[x].V.print();
cerr<<"lazyV:";node[x].lazyV.print();
cerr<<"bool:"<<node[x].lazy<<endl;
cerr<<endl;
if (l == r) {
return;
}
int mid = (l + r) / 2;
print(l, mid, lson(x));
print(mid + 1, r, rson(x));
}
}seg;
int main2(){
freopen("/home/bupt110/in.txt","w",stdout);
srand((int)time(NULL));
int T = 15;
cout<<T<<endl;
while(T--){
int n = 10000;
int Q = 10000;
int M = rand()%(int)((1e9-1) + 1);
cout<<n<<" "<<M<<endl;
for(int i=1;i<=n;i++){
cout<<rand()%(int)((1e9-1) + 1) <<" ";
}
cout<<endl;
cout<<Q<<endl;
for(int i=1;i<=Q;i++){
int kd=rand()%3;
int l=rand()%10000+1 , r = rand()%10000+1;
while(r<l) r = rand() % 10000 + 1;
if(kd==0){
cout<<'Q'<<" "<<l<<" "<<r<<endl;
}else if(kd==1){
cout<<'M'<<" "<<l<<" "<<r<<" "<< rand()%(int)((1e9-1) + 1) <<endl;
}else{
cout<<'D'<<" "<<l<<" "<<r<<" "<< rand()%(int)((1e9-1) + 1) <<endl;
}
}
}
}
int main(){
//freopen("/home/bupt110/in.txt","r",stdin);
getPrm();
int T;scan(T);
for(int Cas = 1;Cas <= T;Cas++){
printf("Case #%d:\n",Cas);
scan2(n,M);
makeMprm();
for(int i=1;i<=n;i++) scan(f[i]);
seg.build(1,n);
int q;
scan(q);
while(q--){
char str[33];
scanf("%s",str);
int l,r;
scan2(l,r);
int len = r-l+1;
if(str[0] == 'Q'){
int res = seg.query(l,r);
printf("%d\n",res);
}else if(str[0] == 'D'){
// cerr<<"--------------------------"<<endl;
// seg.print(1,n);
// cerr<<endl;
int x;scan(x);
PIV piv = trans(x);
//cerr<<piv.first<<":";
piv.first = mod_reverse(piv.first, M);
piv.second.fu();
seg.update(l,r,piv);
// cerr<<"--------------------------"<<endl;
// seg.print(1,n);
// cerr<<endl;
//cerr<<"D:";piv.second.print();
}else if(str[0] == 'M'){
// cerr<<"--------------------------"<<endl;
// seg.print(1,n);
// cerr<<endl;
int x;scan(x);
PIV piv = trans(x);
seg.update(l,r,piv);
// cerr<<"--------------------------"<<endl;
// seg.print(1,n);
// cerr<<endl;
}
}
}
return 0;
}
UESTC 1712 E Easy Problem With Numbers 线段树+互质也可以求逆元
最新推荐文章于 2017-05-16 18:11:23 发布