P8264 [Ynoi Easy Round 2020] TEST_100 题解
怎么题解没一个正解啊(全恼)
首先我们不难发现我们实际要维护的是一个绝对值的复合函数
直接维护的话段数是
考虑从后往前依次加入函数,假设目前已经维护了后
那么不难发现当
当
因为我们已经维护好了后
不难发现这个操作可以用可持久化平衡树维护
然后因为需要支持区间查询,所以我们需要实现的是线段树套平衡树
这样查询时只需要在
而初始化时一共会进行
因此总复杂度为
但是我的实现空间常数很大(也可能是我写的可持久化 fhq_treap 复杂度有问题)
因此还要加两个小优化
第一个是线段树顶层不要二分,而是分为
这样这一层最多在单次查询中多贡献
但是这一部分加入函数的次数就由
第二个是线段树底层不要到区间长度为
因为底层只会有
代码实现比较傻,仅供参考
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<vector>
#include<random>
#define ll long long
using namespace std;
const int MAXN=1e5+10;
const int inf=1e5;
int read()
{
int kkk=0,x=1;
char c=getchar();
while((c<'0' || c>'9') && c!='-') c=getchar();
if(c=='-') c=getchar(),x=-1;
while(c>='0' && c<='9') kkk=kkk*10+(c-'0'),c=getchar();
return kkk*x;
}
int n,m,a[MAXN],ans;
mt19937 gen(time(NULL));
int root[MAXN*2],rcnt,pcnt;
vector<int> son[MAXN*2];
struct fhq_treap
{
int ly,ry;
int size;
int slen;
int l,r;
bool tag;
}tree[MAXN*600];
#define ls(x) (tree[x].l)
#define rs(x) (tree[x].r)
void up(int x)
{
tree[x].size=tree[ls(x)].size+tree[rs(x)].size+1;
tree[x].slen=tree[ls(x)].slen+tree[rs(x)].slen+abs(tree[x].ly-tree[x].ry)+1;
}
int copy(int x)
{
int bck=++pcnt;
tree[bck]=tree[x];
return bck;
}
int check(int x,int y)
{
uniform_int_distribution<int> dcd(1,tree[x].size+tree[y].size);
return dcd(gen)<=tree[x].size;
}
int calc(int o,int len)
{
if(len==1) return tree[o].ly;
else return tree[o].ly+(len-1)*(tree[o].ly>tree[o].ry?-1:1);
}
int NEW(int ly,int ry)
{
int bck=++pcnt;
tree[bck].ly=ly;
tree[bck].ry=ry;
tree[bck].slen=abs(ly-ry)+1;
tree[bck].size=1;
return bck;
}
void turn(int x)
{
tree[x].tag^=1;
swap(ls(x),rs(x));
swap(tree[x].ly,tree[x].ry);
}
void down(int x)
{
if(!tree[x].tag) return;
if(ls(x)) tree[x].l=copy(ls(x)),turn(ls(x));
if(rs(x)) tree[x].r=copy(rs(x)),turn(rs(x));
tree[x].tag=0;
}
int merge(int x,int y)
{
if(!x || !y) return x+y;
int bck;
if(check(x,y))
{
bck=copy(x); down(bck);
tree[bck].r=merge(rs(bck),y);
}
else
{
bck=copy(y); down(bck);
tree[bck].l=merge(x,ls(bck));
}
up(bck);
return bck;
}
void split_len(int x,int len,int &lx,int &rx)
{
if(!x) {lx=rx=0;return;}
if(tree[ls(x)].slen+abs(tree[x].ly-tree[x].ry)+1<=len)
{
lx=copy(x); down(lx);
split_len(rs(lx),len-tree[ls(x)].slen-(abs(tree[x].ly-tree[x].ry)+1),rs(lx),rx);
up(lx);
}
else
{
rx=copy(x); down(rx);
split_len(ls(rx),len,lx,ls(rx));
up(rx);
}
}
void split_size(int x,int size,int &lx,int &rx)
{
if(!x) {lx=rx=0;return;}
if(tree[ls(x)].size+1<=size)
{
lx=copy(x); down(lx);
split_size(rs(lx),size-tree[ls(x)].size-1,rs(lx),rx);
up(lx);
}
else
{
rx=copy(x); down(rx);
split_size(ls(rx),size,lx,ls(rx));
up(rx);
}
}
int find(int &x,int &len,int &S)
{
if(tree[x].tag) x=copy(x),down(x);
if(tree[ls(x)].slen>=len) return find(ls(x),len,S);
else
{
S+=tree[ls(x)].size;
len-=tree[ls(x)].slen;
if(abs(tree[x].ly-tree[x].ry)+1>=len) return x;
else
{
++S;
len-=abs(tree[x].ly-tree[x].ry)+1;
return find(rs(x),len,S);
}
}
}
void get_split_len(int &x,int len,int &lx,int &rx)
{
int tmp=len,S=1;
int o=find(x,tmp,S);
if(abs(tree[o].ly-tree[o].ry)+1!=tmp)
{
int A,B,C,F;
split_size(x,S,F,C);
split_size(F,S-1,A,B);
int D=NEW(tree[o].ly,calc(o,tmp));
int E=NEW(calc(o,tmp+1),tree[o].ry);
lx=merge(A,D);
rx=merge(E,C);
}
else split_len(x,len,lx,rx);
}
void init(int l,int r,int x)
{
for(int i=r;i>=l;--i)
{
int A,B,C,D;
get_split_len(root[x],a[i]+1,A,B);
get_split_len(root[x],inf-a[i]+1,C,B);
get_split_len(C,1,B,D);
turn(A);
root[x]=merge(A,D);
}
}
const int base=2000;
void build(int l,int r,int &x)
{
x=++rcnt;
if(r-l<=1000) return;
if(x==1)
{
int N=(n-1)/base+1;
son[x].resize(N);
for(int i=1;i<=N;++i)
{
build((i-1)*base+1,min(n,i*base),son[x][i-1]);
}
root[x]=NEW(0,inf);
init(l,r,x);
return;
}
int mid=(l+r)>>1;
son[x].resize(2);
build(l,mid,son[x][0]);
build(mid+1,r,son[x][1]);
if(root[son[x][1]])
{
root[x]=copy(root[son[x][1]]);
init(l,mid,x);
}
else
{
root[x]=NEW(0,inf);
init(l,r,x);
}
}
int cx(int l,int r,int L,int R,int v,int x)
{
if(r-l<=1000)
{
for(int i=max(L,l);i<=min(R,r);++i) v=abs(v-a[i]);
return v;
}
if(L<=l && r<=R)
{
++v;
int S=0;
int o=find(root[x],v,S);
return calc(o,v);
}
if(x==1)
{
int N=(n-1)/base+1;
int bck=v;
for(int i=1;i<=N;++i)
{
if(max((i-1)*base+1,L)<=min(min(n,i*base),R)) bck=cx((i-1)*base+1,min(n,i*base),L,R,bck,son[x][i-1]);
}
return bck;
}
int mid=(l+r)>>1;
if(R<=mid) return cx(l,mid,L,R,v,son[x][0]);
if(mid<L) return cx(mid+1,r,L,R,v,son[x][1]);
return cx(mid+1,r,L,R,cx(l,mid,L,R,v,son[x][0]),son[x][1]);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;++i) a[i]=read();
int R;
build(1,n,R);
while(m--)
{
int l=read()^ans,r=read()^ans,v=read()^ans;
printf("%d\n",ans=cx(1,n,l,r,v,R));
}
return 0;
}
//tetu no isi to hagane no tuyosa