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

大兔子大兔子 提交于 2019-12-02 06:38:20

正题

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

      因为对于i到j操作进行询问,所以考虑对操作建一棵线段树,每一个点存有一些区间,对于每一个点,这些区间的并为

,每个区间存有两个值

,对于这个区间内的每一个数k,表示经过我所管理的线段树操作后,会变成

      可以把这些区间转化成多个断点,每次加入一个询问操作会多两个断点,对于线段树上的一条链贡献,所以断点个数总和不超过

,但是遍历一条链,加断点的时间复杂度是不正确的,考虑一棵线段树的子树,当且仅当它满的时候,才把左右儿子进行合并,因为之前不可能访问到线段树中的这个节点。

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

      查询的时候,在线段树上找到对应的节点,二分找到对应的

,把它们合并即可。
 #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); 		} 	} }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!