被xgc吊打的第二天,Rose's simulate,线段树分治

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Deep_Kevin/article/details/102731674

正题

      原题是清华集训2014的玄学。

      因为对于i到j操作进行询问,所以考虑对操作建一棵线段树,每一个点存有一些区间,对于每一个点,这些区间的并为[1,n],每个区间存有两个值(a,b),对于这个区间内的每一个数k,表示经过我所管理的线段树操作后,会变成ax+b

      可以把这些区间转化成多个断点,每次加入一个询问操作会多两个断点,对于线段树上的一条链贡献,所以断点个数总和不超过O(m\log m),但是遍历一条链,加断点的时间复杂度是不正确的,考虑一棵线段树的子树,当且仅当它满的时候,才把左右儿子进行合并,因为之前不可能访问到线段树中的这个节点。

      合并两个端点可以直接过一遍,复杂度跟断点个数相关,所以插入时间复杂度还是O(m \log m)

      查询的时候,在线段树上找到对应的节点,二分找到对应的(a,b),把它们合并即可。

#include<bits/stdc++.h>
#define ls now<<1
#define rs now<<1|1
using namespace std;

const int N=100010;
int T,n,mod,m,t=0;
int A[N];

struct node{
	int l,r,a,b;
	node operator+(const node q)const {return (node){0,0,1ll*a*q.a%mod,(1ll*b*q.a%mod+q.b)%mod};}
}X;
vector<node> tr[N*10];

void calc(int &a,int &b,int c,int d){
	a=1ll*a*c%mod,b=1ll*c*b%mod+d;
	b>=mod?b-=mod:0;
}

void upload(int now){
	int a,b,l=0;
	for(int i=0,j=0;i<tr[ls].size() && j<tr[rs].size();){
		a=tr[ls][i].a;b=tr[ls][i].b;
		calc(a,b,tr[rs][j].a,tr[rs][j].b);
		if(tr[ls][i].r<=tr[rs][j].r){
			tr[now].push_back((node){l+1,tr[ls][i].r,a,b});
			l=tr[ls][i].r;
			if(tr[ls][i].r==tr[rs][j].r) i++,j++;
			else i++;
		}
		else tr[now].push_back((node){l+1,tr[rs][j].r,a,b}),l=tr[rs][j].r,j++;
	}
}

bool insert(int now,int x,int l,int r,node F){
	if(l==r){
		if(F.l>1) tr[now].push_back((node){1,F.l-1,1,0});
		tr[now].push_back(F);
		if(F.r<n) tr[now].push_back((node){F.r+1,n,1,0});
		return true;
	}
	int mid=(l+r)/2;
	if(x<=mid) {insert(ls,x,l,mid,F);return false;}
	else if(insert(rs,x,mid+1,r,F)) {upload(now);return true;}
	else return false;
}

node get_ans(int now,int x,int y,int k,int l,int r){
	if(x==l && y==r){
		int l=0,r=tr[now].size()-1;
		while(l<=r){
			int mid=(l+r)/2;
			if(tr[now][mid].r<k) l=mid+1;
			else if(tr[now][mid].l<=k && k<=tr[now][mid].r) return tr[now][mid];
			else r=mid-1;
		}
	}
	int mid=(l+r)/2;
	if(y<=mid) return get_ans(ls,x,y,k,l,mid);
	else if(mid<x) return get_ans(rs,x,y,k,mid+1,r);
	else return get_ans(ls,x,mid,k,l,mid)+get_ans(rs,mid+1,y,k,mid+1,r);
}

int main(){
	scanf("%d %d %d",&T,&n,&mod);T=T&1;
	for(int i=1;i<=n;i++) scanf("%d",&A[i]);
	scanf("%d",&m);
	int tot=m;
	int type,x,y,a,b;
	long long last=0;
	while(m--){
		scanf("%d %d %d %d",&type,&x,&y,&a);
		if(T) x^=last,y^=last; 
		if(!type){
			scanf("%d",&b);
			t++;insert(1,t,1,tot,(node){x,y,a,b});
		}
		else{
			if(T) a^=last;
			X=get_ans(1,x,y,a,1,tot);
			printf("%lld\n",last=(1ll*A[a]*X.a%mod+X.b)%mod);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/102731674