1 条题解
-
0
自动搬运
来自洛谷,原作者为

zhy12138
AFOed搬运于
2025-08-24 22:37:28,当前版本为作者最后更新于2022-07-22 09:10:24,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
怎么题解没一个正解啊(全恼)
首先我们不难发现我们实际要维护的是一个绝对值的复合函数
直接维护的话段数是 级别的,所以考虑用一些特殊的数据结构维护
考虑从后往前依次加入函数,假设目前已经维护了后 个的复合函数,现在正在加入倒数第 个函数
那么不难发现当 在 中, 是
当 在 中, 是
因为我们已经维护好了后 个的复合函数,那么我们只需要拿出这个复合函数的 两段,然后将前一段反转再拼接即可
不难发现这个操作可以用可持久化平衡树维护
然后因为需要支持区间查询,所以我们需要实现的是线段树套平衡树
这样查询时只需要在 个节点中花费 的复杂度找到对应的段,然后求值即可,复杂度
而初始化时一共会进行 次在前面加函数的操作,每次操作的复杂度是
因此总复杂度为
但是我的实现空间常数很大(也可能是我写的可持久化 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
- 1
信息
- ID
- 7602
- 时间
- 2000ms
- 内存
- 2048MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者