题目
UOJ
强制在线
思路
定义运算为
,建立以时间为下标的线段树
则左右儿子,分别为
和
上传标记后为
即
1.非强制在线
可将询问按
排序后拆分线段扫描线,查询直接线段树上查即可
时间复杂度
2.强制在线
线段树如上,但对于线段树一个节点
代表维护进行
修改操作后整个序列对应运算
但是如果直接维护空间是
级别的
我们可以维护连续相同的运算
合并左右儿子用类似归并的方法
发现如果节点代表时间区间长度为
那么空间开销为
数量级,于是整个线段树空间开销为
查询操作需要二分出位置在哪一段 单次,
修改不能按照常规操作会退化成 单次
,很巧妙,对于
时刻只对于节点右端点不大于
的区间进行上传操作均摊
于是总时间复杂度为
代码
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstring>
#include<climits>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
//#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
inline int read() {
bool f=0;int x=0;char c=getchar();
while(c<'0'||'9'<c){if(c==EOF)exit(0);if(c=='-')f=1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
#define lch (u<<1)
#define rch (u<<1|1)
#define MAXN 600000
#define INF 0x3f3f3f3f
struct Tran{
int r,a,b;
}node[20*MAXN+5];
int n,Mod,num[MAXN+5];
int ncnt,L[5*MAXN+5],R[5*MAXN+5];
void PushUp(int u){
L[u]=ncnt+1;
int lsiz=R[lch],rsiz=R[rch],p=L[lch],q=L[rch];
while(p<=lsiz&&q<=rsiz){
node[++ncnt]=(Tran){min(node[p].r,node[q].r),1ll*node[p].a*node[q].a%Mod,(1ll*node[p].b*node[q].a%Mod+node[q].b)%Mod};
if(node[p].r<node[q].r) p++;
else if(node[p].r>node[q].r) q++;
else p++,q++;
}
while(p<=lsiz) node[++ncnt]=node[p++];
while(q<=rsiz) node[++ncnt]=node[q++];
R[u]=ncnt;
return ;
}
int a,b;
void Insert(int u,int tL,int tR,int pL,int pR,int tp){
if(tL==tR){
L[u]=ncnt+1;
if(pL>1) node[++ncnt]=(Tran){pL-1,1,0};
node[++ncnt]=(Tran){pR,a,b};
if(pR<n) node[++ncnt]=(Tran){n,1,0};
R[u]=ncnt;
return ;
}
int Mid=(tL+tR)>>1;
if(tp<=Mid)
Insert(lch,tL,Mid,pL,pR,tp);
else Insert(rch,Mid+1,tR,pL,pR,tp);
if(tp==tR)
PushUp(u);
return ;
}
int A,B;
void BS(int u,int p){
int l=L[u]-1,r=R[u];
while(l+1<r){
int mid=(l+r)>>1;
if(p<=node[mid].r) r=mid;
else l=mid;
}
A=1ll*A*node[r].a%Mod,B=(1ll*B*node[r].a%Mod+node[r].b)%Mod;
return ;
}
void Query(int u,int tL,int tR,int qL,int qR,int p){
if(qL<=tL&&tR<=qR){
BS(u,p);
return ;
}
int Mid=(tL+tR)>>1;
if(qL<=Mid) Query(lch,tL,Mid,qL,qR,p);
if(Mid+1<=qR) Query(rch,Mid+1,tR,qL,qR,p);
return ;
}
int main(){
int kind=read()&1,lastans=0,qcnt=0;
n=read(),Mod=read();
for(int i=1;i<=n;i++)
num[i]=read();
int q=read();
for(int t=1;t<=q;t++){
int opt=read();
if(opt==1){
int i=read(),j=read();a=read(),b=read();
if(kind) i^=lastans,j^=lastans;
Insert(1,1,q,i,j,++qcnt);
}
else{
int i=read(),j=read(),k=read();
if(kind) i^=lastans,j^=lastans,k^=lastans;
A=1,B=0;
Query(1,1,q,i,j,k);
lastans=(1ll*A*num[k]%Mod+B)%Mod;
printf("%d\n",lastans);
}
}
return 0;
}
思考
时间+区间修改+离线要多联系线段树中扫描线技巧,强制在线想办法优化空间