一、题目
二、解法
我学懂了!!!!
这道题可以写无旋 treap \text{treap} treap,最近学了 splay \text{splay} splay,我就讲一下它的操作吧。
这道题我们需要维护权值和最大值,那么我们如何查区间呢?我们先多建两个哨兵节点(一共 n + 2 n+2 n+2个点),然后我们把排名为 l l l的点 A A A转到根去,再把排名为 r + 2 r+2 r+2的点 B B B转到 A A A的右儿子(这里的排名要考虑哨兵),如果我们把 [ l , r ] [l,r] [l,r]的区间看成一个点的话,那么这个点是 B B B的左儿子,然后我们直接对 B B B的左儿子去打标记,或者是询问。
我们怎么维护标记呢?在旋转的时候我们需要下传标记,在查排名的时候也要下传标记,然后就完了 q w q qwq qwq。
#include <cstdio>
#include <iostream>
using namespace std;
#define inf 0x3f3f3f3f
const int M = 200005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,rt,ncnt,ch[M][2],val[M],Max[M],par[M],siz[M],fl[M],la[M];
void push_up(int x)
{
if(!x) return ;
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
Max[x]=max(max(Max[ch[x][0]],Max[ch[x][1]]),val[x]);
}
void flip(int x)
{
if(!x) return ;
swap(ch[x][0],ch[x][1]);
fl[x]^=1;
}
void add(int x,int c)
{
if(!x) return ;
Max[x]+=c;val[x]+=c;
la[x]+=c;
}
void push_down(int x)
{
if(fl[x])
{
flip(ch[x][0]);flip(ch[x][1]);
fl[x]=0;
}
if(la[x])
{
add(ch[x][0],la[x]);add(ch[x][1],la[x]);
la[x]=0;
}
}
int chk(int x)
{
return ch[par[x]][1]==x;
}
void rotate(int x)
{
int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
push_down(y);push_down(x);
ch[y][k]=w;par[w]=y;
ch[z][chk(y)]=x;par[x]=z;
ch[x][k^1]=y;par[y]=x;
push_up(y);push_up(x);
}
void splay(int x,int goal=0)
{
while(par[x]^goal)
{
int y=par[x],z=par[y];
if(z!=goal)
{
if(chk(x)==chk(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
if(!goal) rt=x;
}
int find(int k)
{
int cur=rt;
while(1)
{
push_down(cur);
if(ch[cur][0] && k<=siz[ch[cur][0]])
cur=ch[cur][0];
else if(k>siz[ch[cur][0]]+1)
{
k-=siz[ch[cur][0]]+1;
cur=ch[cur][1];
}
else return cur;
}
}
int main()
{
Max[0]=-inf;
n=read();m=read();
rt=1;
for(int i=1;i<=n+2;i++)
{
siz[i]=n+3-i;
if(i) {ch[i-1][1]=i;par[i]=i-1;}
}
while(m--)
{
int op=read(),l=read(),r=read();
if(op==1)
{
int a=find(l),b=find(r+2);
splay(a);splay(b,a);
add(ch[b][0],read());
}
if(op==2)
{
int a=find(l),b=find(r+2);
splay(a);splay(b,a);
flip(ch[b][0]);
}
if(op==3)
{
int a=find(l),b=find(r+2);
splay(a);splay(b,a);
printf("%d\n",Max[ch[b][0]]);
}
}
}