【BZOJ3821】【UOJ#46】【清华集训2014】—玄学(线段树分治)

UOJ传送门

我们发现实际上可以不用在乎给出的xx,可以先记录一个a,ba,b的系数
显然这个每次很好计算贡献
显然离线的时候我们可以用线段树分治氵过去
那在线呢?
二进制分组?
好像不太行得通,因为在一个组内可能只取一部分
继续考虑线段树分治
显然在一个操作出现之前不会被统计到
那就可以在每次加一次操作后对于已经填满的区间pushuppushup一下

突然发现似乎pushuppushup有点问题
我们没有办法每个节点维护一个序列表示被怎么修改,那样是O(n2)O(n^2)

但我们发现每次修改其实最多只会在原来的基础上增加22个区间(考虑只有左右端点会切割出多的区间,其他的都是整体增加)

考虑对每个节点维护一个vectorvector记录一下有哪些区间
合并信息的时候可以维护双指针

每次询问的时候按照线段树分治的老套路
对于一个整区间二分找到询问点的信息返回

更具体的可以参考代码

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    return res*f;
}
const int N=100005;
int type,n,q,tot,mod,pre,a[N];
inline void calc(int &a,int &b,int x,int y){
	a=1ll*a*x%mod,b=(1ll*b*x+y)%mod;
}
struct node{
	int l,r,a,b;
	node(int _l,int _r,int _a,int _b):l(_l),r(_r),a(_a),b(_b){}
	friend inline node operator +(node a,const node &b){
		calc(a.a,a.b,b.a,b.b);return a;
	}
};
vector<node>tr[N<<2];
#define pb push_back
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
void build(int u,int l,int r){
	tr[u].pb(node(1,n,1,0));
	if(l==r)return;
	build(lc,l,mid),build(rc,mid+1,r);
}
inline void pushup(int u){
	tr[u].clear();
	for(int i=0,j=0,l=0;i<tr[lc].size()&&j<tr[rc].size();){
		int a=tr[lc][i].a,b=tr[lc][i].b;
		calc(a,b,tr[rc][j].a,tr[rc][j].b);
		if(tr[lc][i].r<=tr[rc][j].r){
			tr[u].pb(node(l+1,tr[lc][i].r,a,b));
			l=tr[lc][i].r;
			if(tr[lc][i].r==tr[rc][j].r)i++,j++;
			else i++;
		}
		else {
			tr[u].pb(node(l+1,tr[rc][j].r,a,b));
			l=tr[rc][j].r,j++;
		}
	}
}
bool update(int u,int l,int r,int p,node k){
	if(l==r){
		if(k.l!=1)tr[u].pb(node(1,k.l-1,1,0));
		tr[u].pb(k);
		if(k.r!=n)tr[u].pb(node(k.r+1,n,1,0));
		return true;
	}
	if(p<=mid){update(lc,l,mid,p,k);return false;}
	else{
		bool flag=update(rc,mid+1,r,p,k);
		if(flag)pushup(u);
		return true;
	}
}
node query(int u,int l,int r,int st,int des,int k){
	if(st==l&&r==des){
		int L=0,R=tr[u].size();
		while(L<=R){
			int mi=(L+R)>>1;
			if(tr[u][mi].l<=k&&k<=tr[u][mi].r)return tr[u][mi];
			if(tr[u][mi].r<k)L=mi+1;
			else R=mi-1;
		}
	}
	if(des<=mid)return query(lc,l,mid,st,des,k);
	if(mid<st)return query(rc,mid+1,r,st,des,k);
	return query(lc,l,mid,st,mid,k)+query(rc,mid+1,r,mid+1,des,k);	
}
int main(){
	type=read()&1;
	n=read(),mod=read();
	for(int i=1;i<=n;i++)a[i]=read();
	q=read();
	while(q--){
		int op=read(),l=read(),r=read();
		if(type)l^=pre,r^=pre;
		switch(op){
			case 1:{
				int a=read(),b=read();
				tot++,update(1,1,N-5,tot,node(l,r,a,b));
				break;
			}
			case 2:{
				int p=read();if(type)p^=pre;
				node now=query(1,1,N-5,l,r,p);
				cout<<(pre=((1ll*now.a*a[p]+now.b)%mod))<<'\n';
				break;
			}
		}
	}
}
posted @ 2019-03-08 16:17  Stargazer_cykoi  阅读(123)  评论(0编辑  收藏  举报