寒假集训 | 线段树大杂烩(线段树,主席树,树套树,线段树合并&分裂)解题报告
Update on 2025/2/25
Update on 2025/02/12
题目列表:
SP1043 GSS1 - Can you answer these queries I:静态区间最大子段和
SP1716 GSS3 - Can you answer these queries III:单点修改区间最大子段和
P6327 区间加区间 sin 和:用和差化积把修改展开,维护区间 cos,sin 和
P1908 逆序对:权值线段树入门题,从前往后枚举位置,这个位置的逆序对数就是线段树中 \(> a_i\) 的数的个数。
点击查看 P1908 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int a[1<<20];
unordered_map<int,int> mp;
const int MINN=1;
int MAXN=1e9;
int n;
struct Tree{
int cnt,lp,rp;
}tree[2000005];
int b[1<<20];
int tot;
void pushup(Tree &p,const Tree &lp,const Tree &rp)
{
p.cnt=lp.cnt+rp.cnt;
}
void add(int l,int r,const int &x,int &p)
{
if(!p) p=++tot;
if(l==r&&l==x)
{
tree[p].cnt++;
return;
}
int mid=l+((r-l)>>1);
if(x<=mid) add(l,mid,x,tree[p].lp);
if(x>mid) add(mid+1,r,x,tree[p].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
}
int query(int l,int r,const int &sl,const int &sr,int p)
{
if(!p) return 0;
if(sl<=l&&r<=sr) return tree[p].cnt;
// cout<<l<<" "<<r<<"\n";
int mid=l+((r-l)>>1),lp=tree[p].lp,rp=tree[p].rp,ans=0;
if(sl<=mid) ans+=query(l,mid,sl,sr,lp);
if(mid+1<=sr) ans+=query(mid+1,r,sl,sr,rp);
return ans;
}
signed main()
{
//mt19937_64 myrand(time(0));
n=read();
long long ans=0;
int root=0;
for(int i=1;i<=n;i++) b[i]=a[i]=read();
sort(a+1,a+1+n);
a[0]=-1;
a[n+1]=999999999999;
for(int i=1;i<=n+1;i++)
if(a[i]!=a[i-1]) mp[a[i]]=++tot;
MAXN=tot;
tot=0;
for(int i=1;i<=n;i++)
{
int x=mp[b[i]];
// cout<<"tot="<<tot<<" x="<<x<<" "<<query(MINN,MAXN,MINN,x,root)<<" ";
ans+=i-1-query(MINN,MAXN,MINN,x,root);
// cout<<ans<<" \n";
add(MINN,MAXN,x,root);
}
// cout<<"\n";
write(ans);
return 0;
}
P1637 三元上升子序列:权值线段树更麻烦一点的入门题。枚举中间位置 j,在 j 前面的数建权值线段树 1,在 j 后面的数建权值线段树 2,答案显然。
点击查看 P1637 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n;
int a[1<<20];
const int MINN=0,MAXN=1e5;
struct Node{
struct Tree{
int lp,rp,sum;
}tree[2000005];
int tot=0;
int root=0;
void pushup(Tree &p,Tree lp,Tree rp)
{
p.sum=lp.sum+rp.sum;
}
void add(int l,int r,int x,int op,int &p)
{
if(!p) p=++tot;
if(l==r&&l==x)
{
tree[p].sum+=op;
return;
}
int mid=(l+r)>>1;
if(x<=mid) add(l,mid,x,op,tree[p].lp);
if(x>mid) add(mid+1,r,x,op,tree[p].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
}
int query(int l,int r,int sl,int sr,int p)
{
if(!p) return 0;
if(sl<=l&&r<=sr) return tree[p].sum;
int mid=(l+r)>>1,lp=tree[p].lp,rp=tree[p].rp,ans=0;
if(sl<=mid) ans+=query(l,mid,sl,sr,lp);
if(mid+1<=sr) ans+=query(mid+1,r,sl,sr,rp);
return ans;
}
}tree[2];
signed main()
{
//mt19937_64 myrand(time(0));
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=2;i<=n;i++) tree[1].add(MINN,MAXN,a[i],1,tree[1].root);
int ans=0;
for(int mid=2;mid<n;mid++)
{
tree[0].add(MINN,MAXN,a[mid-1],1,tree[0].root);
tree[1].add(MINN,MAXN,a[mid],-1,tree[1].root);
ans+=tree[0].query(MINN,MAXN,MINN,a[mid]-1,tree[0].root)*(n-mid-tree[1].query(MINN,MAXN,MINN,a[mid],tree[0].root));
}
write(ans);
return 0;
}
P3369 【模板】普通平衡树:权值线段树模板题。
点击查看 P3369 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int MAXN=1e7,MINN=-1e7;
int n,tot;
struct Tree{
int l,r,lp,rp,num;
}tree[1<<23];
void pushup(Tree &p,const Tree &lp,const Tree &rp)
{
p.num=lp.num+rp.num;
}
void build(int &p,const int &l,const int &r)
{
p=++tot;
tree[p].l=l;
tree[p].r=r;
}
void add(int l,int r,const int &x,const int &op,int &p)
{
if(!p) build(p,l,r);
if(l==r)
{
tree[p].num+=op;
tree[p].num=max(tree[p].num,0ll);
return;
}
int mid=(l+r)>>1;
if(x<=mid) add(l,mid,x,op,tree[p].lp);
if(mid+1<=x) add(mid+1,r,x,op,tree[p].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
}
int query(int l,int r,const int &sl,const int &sr,int p)
{
if(sl>sr) return 0;
if(!p) return 0;
if(sl<=l&&r<=sr) return tree[p].num;
int mid=(l+r)>>1,lp=tree[p].lp,rp=tree[p].rp,ans=0;
if(sl<=mid) ans+=query(l,mid,sl,sr,lp);
if(sr>=mid+1) ans+=query(mid+1,r,sl,sr,rp);
return ans;
}
int kth(int l,int r,int k,int p)
{
if(!p) return 0;
if(l==r) return l;
int mid=(l+r)>>1,lp=tree[p].lp,rp=tree[p].rp;
if(tree[lp].num>=k) return kth(l,mid,k,lp);
if(tree[lp].num<k) return kth(mid+1,r,k-tree[lp].num,rp);
return 0;
}
signed main()
{
n=read();
int root=0;
for(int i=1;i<=n;i++)
{
int op=read(),x=read();
if(op==1) add(MINN,MAXN,x,1,root);
if(op==2) add(MINN,MAXN,x,-1,root);
if(op==3) write(query(MINN,MAXN,MINN,x-1,root)+1),putchar('\n');
if(op==4) write(kth(MINN,MAXN,x,root)),putchar('\n');
if(op==5) write(kth(MINN,MAXN,query(MINN,MAXN,MINN,x-1,root),root)),putchar('\n');
if(op==6) write(kth(MINN,MAXN,query(MINN,MAXN,MINN,x,root)+1,root)),putchar('\n');
}
return 0;
}
P3834 【模板】可持久化线段树 2:主席树板子(可持久化动态开点权值线段树)
点击查看 P3834 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int MINN=1;
int MAXN;
int tot;
int root[1<<20];
int n,m;
int a[1<<20];
struct Tree{
int lp,rp,sum;
int l,r;
}tree[1<<22];
unordered_map<int,int> mp;
int num[1<<20];
int b[1<<20];
void pushup(Tree &p,const Tree &lp,const Tree &rp)
{
p.sum=lp.sum+rp.sum;
}
void add(int l,int r,int x,int &nwp,int lastp)
{
if(!nwp) nwp=++tot;
tree[nwp].l=l;
tree[nwp].r=r;
if(l==r&&r==x)
{
tree[nwp].sum=tree[lastp].sum+1;
return;
}
int mid=(l+r)>>1;
if(x<=mid) tree[nwp].rp=tree[lastp].rp,add(l,mid,x,tree[nwp].lp,tree[lastp].lp);
if(x>mid) tree[nwp].lp=tree[lastp].lp,add(mid+1,r,x,tree[nwp].rp,tree[lastp].rp);
pushup(tree[nwp],tree[tree[nwp].lp],tree[tree[nwp].rp]);
}
int query(int l,int r,int k,int nwp,int lastp)
{
if(l==r) return l;
int mid=(l+r)>>1;
int nw=tree[tree[nwp].lp].sum-tree[tree[lastp].lp].sum;
if(nw>=k) return query(l,mid,k,tree[nwp].lp,tree[lastp].lp);
if(nw<k) return query(mid+1,r,k-nw,tree[nwp].rp,tree[lastp].rp);
}
signed main()
{
n=read();
m=read();
for(int i=1;i<=n;i++) b[i]=a[i]=read();
sort(a+1,a+1+n);
a[0]=-1;
a[n+1]=9999999999999;
for(int i=1;i<=n;i++)
if(a[i]!=a[i+1]) ++tot,num[tot]=a[i],mp[a[i]]=tot;
for(int i=1;i<=n;i++) b[i]=mp[b[i]];
MAXN=tot;
tot=0;
for(int i=1;i<=n;i++) add(MINN,MAXN,b[i],root[i],root[i-1]);
while(m--)
{
int l=read(),r=read(),k=read();
write(num[query(MINN,MAXN,k,root[r],root[l-1])]);
putchar('\n');
}
return 0;
}
P3919 【模板】可持久化线段树 1(可持久化数组):可持久化普通线段树
点击查看 P3919 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int m,n;
int a[1<<20];
struct Tree{
int val,lp,rp;
}tree[1<<25];
int tot;
int root[1<<20];
void build(int l,int r,int &p)
{
if(!p) p=++tot;
if(l==r)
{
tree[p].val=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,tree[p].lp);
build(mid+1,r,tree[p].rp);
}
void add(int l,int r,int p,int x,int &nwp,int lastp)
{
if(!nwp) nwp=++tot;
if(l==r)
{
tree[nwp].val=x;
return;
}
int mid=(l+r)>>1;
if(p<=mid) tree[nwp].rp=tree[lastp].rp,add(l,mid,p,x,tree[nwp].lp,tree[lastp].lp);
if(p>mid) tree[nwp].lp=tree[lastp].lp,add(mid+1,r,p,x,tree[nwp].rp,tree[lastp].rp);
}
int query(int l,int r,const int &p,int nwp)
{
if(l==r) return tree[nwp].val;
int mid=(l+r)>>1;
if(p<=mid) return query(l,mid,p,tree[nwp].lp);
return query(mid+1,r,p,tree[nwp].rp);
}
signed main()
{
n=read();
m=read();
for(int i=1;i<=n;i++) a[i]=read();
build(1,n,root[0]);
for(int i=1;i<=m;i++)
{
int v=read(),op=read(),loc=read();
if(op==1) add(1,n,loc,read(),root[i],root[v]);
if(op==2) root[i]=root[v],write(query(1,n,loc,root[v])),putchar('\n');
}
return 0;
}
P1383 高级打字机:可持久化普通线段树
P3567 [POI 2014] KUR-Couriers:主席树
P7261 [COCI 2009/2010 #3] PATULJCI:P3567 的双倍经验
SP5652 PATULJCI - Snow White and the N dwarfs:P7261 的双倍经验
P7252 [JSOI2011] 棒棒糖:P7261 的双倍经验
P2617 Dynamic Rankings:树套树的简单模板题(树状数组套普通动态开点权值线段树)
P1533 可怜的狗狗:主席树
SP3946 MKTHNUM - K-th Number:主席树(静态区间第 k 小)
P3380 【模板】树套树:树套树的模板题(树状数组套普通动态开点权值线段树)
点击查看 P3380 代码
#include<bits/stdc++.h>
#define int long l
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,m;
int a[1<<20];
int tot;
struct Tree{
int cnt,lp,rp;
}tree[1<<24];
int root[1<<20];
const int MINN=0,MAXN=1e8;
int cnt[2],tmp[2][105];
int lowbit(int x) { return x&(-x); }
void pushup(Tree &p,Tree lp,Tree rp)
{
p.cnt=lp.cnt+rp.cnt;
if(p.cnt<0) p.cnt=0;
}
void add(int l,int r,int val,const int op,int &p)
{
if(!p) p=++tot;
// tree[p].cnt+=op;
// if(tree[p].cnt<0) tree[p].cnt=0;
if(l==r)
{
tree[p].cnt+=op;
if(tree[p].cnt<0) tree[p].cnt=0;
return;
}
int mid=(l+r)>>1;
if(val<=mid) add(l,mid,val,op,tree[p].lp);
else add(mid+1,r,val,op,tree[p].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
}
void prepare_add(int root_id,int val,const int op)
{
for(int i=root_id;i<=n;i+=lowbit(i))
add(MINN,MAXN,val,op,root[i]);
}
void prepare(int lroot,int rroot)
{
memset(tmp,0,sizeof(tmp));
cnt[0]=cnt[1]=0;
for(int i=lroot;i>0;i-=lowbit(i)) tmp[0][++cnt[0]]=root[i];
for(int i=rroot;i>0;i-=lowbit(i)) tmp[1][++cnt[1]]=root[i];
}
int query(int l,int r,int x)//x 的排名
{
if(l==r) return 1;
int mid=(l+r)>>1;
int nw=0;
if(x<=mid)
{
for(int i=1;i<=cnt[1];i++) tmp[1][i]=tree[tmp[1][i]].lp;
for(int i=1;i<=cnt[0];i++) tmp[0][i]=tree[tmp[0][i]].lp;
return query(l,mid,x);
}
for(int i=1;i<=cnt[1];i++) nw+=tree[tree[tmp[1][i]].lp].cnt,tmp[1][i]=tree[tmp[1][i]].rp;
for(int i=1;i<=cnt[0];i++) nw-=tree[tree[tmp[0][i]].lp].cnt,tmp[0][i]=tree[tmp[0][i]].rp;
return nw+query(mid+1,r,x);
}
int kth(int l,int r,int k)//排名为 k 的值
{
if(k<1) return -2147483647;
// if() return 2147483647;
if(l==r) return l;
int mid=(l+r)>>1,nw=0;
for(int i=1;i<=cnt[1];i++) nw+=tree[tree[tmp[1][i]].lp].cnt;
for(int i=1;i<=cnt[0];i++) nw-=tree[tree[tmp[0][i]].lp].cnt;
if(nw>=k)
{
for(int i=1;i<=cnt[1];i++) tmp[1][i]=tree[tmp[1][i]].lp;
for(int i=1;i<=cnt[0];i++) tmp[0][i]=tree[tmp[0][i]].lp;
return kth(l,mid,k);
}
else
{
for(int i=1;i<=cnt[1];i++) tmp[1][i]=tree[tmp[1][i]].rp;
for(int i=1;i<=cnt[0];i++) tmp[0][i]=tree[tmp[0][i]].rp;
return kth(mid+1,r,k-nw);
}
}
signed main()
{
n=read();
m=read();
for(int i=1;i<=n;i++) a[i]=read(),prepare_add(i,a[i],1);
while(m--)
{
int op=read();
if(op==3)
{
int pos=read(),k=read();
prepare_add(pos,a[pos],-1);
a[pos]=k;
prepare_add(pos,a[pos],1);
continue;
}
int l=read(),r=read(),k=read(),nw=0;
prepare(l-1,r);
if(op==1) write(query(MINN,MAXN,k));
if(op==2) write(kth(MINN,MAXN,k));
if(op==4) nw=query(MINN,MAXN,k)-1,prepare(l-1,r),write(kth(MINN,MAXN,nw));
if(op==5) nw=query(MINN,MAXN,k+1),prepare(l-1,r),write(((nw<=(r-l+1))?kth(MINN,MAXN,nw):2147483647));
putchar('\n');
}
//mt19937_64 myrand(time(0));
return 0;
}
P3835 【模板】可持久化平衡树:树套树的模板题(树状数组套普通动态开点权值线段树)
代码与 P3380 极为类似。
点击查看 P3835 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int MINN=-2147483647,MAXN=2147483647;
int n;
int root[1<<20];
struct Tree{
int cnt,lp,rp;
}tree[32000005];
int tot;
void pushup(Tree &p,Tree lp,Tree rp)
{
p.cnt=lp.cnt+rp.cnt;
}
void add(int l,int r,int val,const int op,int &nwp,int lastp)
{
if(!nwp) nwp=++tot;
if(l==r)
{
tree[nwp].cnt+=tree[lastp].cnt+op;
if(tree[nwp].cnt<0) tree[nwp].cnt=0;
return;
}
int mid=(l+r)>>1;
if(val<=mid) tree[nwp].rp=tree[lastp].rp,add(l,mid,val,op,tree[nwp].lp,tree[lastp].lp);
else tree[nwp].lp=tree[lastp].lp,add(mid+1,r,val,op,tree[nwp].rp,tree[lastp].rp);
pushup(tree[nwp],tree[tree[nwp].lp],tree[tree[nwp].rp]);
}
int query(int l,int r,int x,int p) //查询 x 的排名
{
// if(!p) return 0;
if(l==r) return 1;
int mid=(l+r)>>1;
if(x<=mid) return query(l,mid,x,tree[p].lp);
else return tree[tree[p].lp].cnt+query(mid+1,r,x,tree[p].rp);
}
int kth(int l,int r,int k,int p)
{
// if(k<1) return -2147483647;
if(l==r) return l;
int mid=(l+r)>>1;
int nw=tree[tree[p].lp].cnt;
if(k<=nw) return kth(l,mid,k,tree[p].lp);
else return kth(mid+1,r,k-nw,tree[p].rp);
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
int v=read(),op=read(),x=read();
if(op==1)
{
add(MINN,MAXN,x,1,root[i],root[v]);
continue;
}
if(op==2)
{
add(MINN,MAXN,x,-1,root[i],root[v]);
continue;
}
root[i]=root[v];
if(op==3) write(query(MINN,MAXN,x,root[i]));
if(op==4) write(kth(MINN,MAXN,x,root[i]));
if(op==5) write(kth(MINN,MAXN,query(MINN,MAXN,x,root[i])-1,root[i]));
if(op==6) write(kth(MINN,MAXN,query(MINN,MAXN,x+1,root[i]),root[i]));/*nw=query(MINN,MAXN,x+1,root[i]),cout<<"nw="<<nw<<" ",write(((nw>tree[root[i]].cnt)?kth(MINN,MAXN,nw,root[i]):2147483647));*/
putchar('\n');
}
// for(int i=1;i<=n;i++)cout<<root[i]<<" ";
// cout<<"\n";
//mt19937_64 myrand(time(0));
return 0;
}
P6166 [IOI 2012] scrivener:P1383 的双倍经验
P1972 [SDOI2009] HH的项链:使用主席树可以在线处理
点击查看 P4587 代码
#include<bits/stdc++.h>
#define int long l
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n;
int a[1<<20];
int root[1<<20];
int tot;
const int MINN=-2,MAXN=1e9+2;
struct Tree{
int sum,cnt,lp,rp,l,r;
}tree[100005*32];
void pushup(Tree &p,Tree lp,Tree rp)
{
p.cnt=lp.cnt+rp.cnt;
p.sum=lp.sum+rp.sum;
}
void add(int l,int r,int val,int &p,int lastp)
{
if(!p) p=++tot;
tree[p].l=l;
tree[p].r=r;
if(l==r)
{
tree[p].cnt=tree[lastp].cnt+1;
tree[p].sum=tree[lastp].sum+val;
return;
}
int mid=(l+r)>>1;
if(val<=mid) tree[p].rp=tree[lastp].rp,add(l,mid,val,tree[p].lp,tree[lastp].lp);
else tree[p].lp=tree[lastp].lp,add(mid+1,r,val,tree[p].rp,tree[lastp].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
}
int getsum(int l,int r,int val,int p,int lastp)//<=val ????
{
if(l==r) return tree[p].sum-tree[lastp].sum;
int mid=(l+r)>>1;
if(val<=mid) return getsum(l,mid,val,tree[p].lp,tree[lastp].lp);
else return tree[tree[p].lp].sum-tree[tree[lastp].lp].sum+getsum(mid+1,r,val,tree[p].rp,tree[lastp].rp);
}
int kth(int l,int r,int k,int p,int lastp)//??? k ???
{
if(l==r) return l;
int mid=(l+r)>>1;
int nw=tree[tree[p].lp].cnt-tree[tree[lastp].lp].cnt;
if(nw>=k) return kth(l,mid,k,tree[p].lp,tree[lastp].lp);
else return kth(mid+1,r,k-nw,tree[p].rp,tree[lastp].rp);
}
int query(int l,int r,int val,int p,int lastp)//val ???
{
if(l==r) return 1;
int mid=(l+r)>>1;
if(val<=mid) return query(l,mid,val,tree[p].lp,tree[lastp].lp);
else return tree[tree[p].lp].cnt-tree[tree[lastp].lp].cnt+query(mid+1,r,val,tree[p].rp,tree[lastp].rp);
}
signed main()
{
//mt19937_64 myrand(time(0));
// freopen("data.out","r",stdin);
// freopen("ans2.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) a[i]=read(),add(MINN,MAXN,a[i],root[i],root[i-1]);
int m=read();
// for(int i=0;i<=tot;i++)
// {
// cout<<"id="<<i<<" tree[p].l="<<tree[i].l<<" tree[p].r="<<tree[i].r<<" btree[i].lp= "<<tree[i].lp<<" "<<"tree[i].rp="<<tree[i].rp<<" tree[i].cnt="<<tree[i].cnt<<" tree[i].sum="<<tree[i].sum<<"\n";
// if(tree[i].lp+tree[i].rp==0) cout<<"\n";
// }
while(m--)
{
int l=read(),r=read();
// int k=read();
int nw=1;
while(1)
{
int nww=getsum(MINN,MAXN,nw,root[r],root[l-1]);
/*这行是和题解拍出来的*/while(nww!=nw) nw=nww,nww=getsum(MINN,MAXN,nw,root[r],root[l-1])/*,cout<<"m="<<m<<"nw="<<nw<<"\n"*/;
// cout<<"m="<<m<<" nw="<<nw<<" kth="<<kth(MINN,MAXN,query(MINN,MAXN,nw,root[r],root[l-1]),root[r],root[l-1])<<"\n";
nw++;
if(nw!=kth(MINN,MAXN,query(MINN,MAXN,nw,root[r],root[l-1]),root[r],root[l-1]))
break;
}
write(nw);
putchar('\n');
// cout<<kth(MINN,MAXN,k,root[r],root[l-1])<<" ";
// cout<<query(MINN,MAXN,k,root[r],root[l-1])<<" ";
// cout<<getsum(MINN,MAXN,k,root[r],root[l-1])<<" \n";
}
return 0;
}
/*
5
1 4 2 3 5
4
1 5 1
2 3 2
2 4 1
3 5 1
*/
P1110 [ZJOI2007] 报表统计:史,需要将普通权值线段树空间压缩到极致才能卡着 0.5 Mib 过,(好像假了)懒得写优化了(咕)。
P2343 宝石管理系统:普通动态开点权值线段树,带修全局第 k 大
P8701 [蓝桥杯 2019 国 B] 第八大奇迹:带修区间第 k 大,树套树实现
P3224 [HNOI2012] 永无乡:(权值)线段树合并简单模板题,如果两棵线段树上两个节点都存在,则继续递归,边界为有 \(\ge 1\) 棵树没有节点或当前节点为叶子节点,则不再递归。
点击查看 P3224 代码
```cpp #includeusing namespace std;
const int Size=(1<<20)+1;
char buf[Size],p1=buf,p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt)
? EOF
: ss++)
char In[1<<20],ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline char readc()
{
char c=getchar();
for(;c<'A'||c>'Z';c=getchar());
return c;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int MINN=-1,MAXN=3e5+1;
int n,m;
int p[1<<20];
int root[1<<20];
struct Tree{
int lp,rp,cnt;
}tree[300005*19];
int tot;
int fa[1<<20];
int find(int x)
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void pushup(Tree &p,Tree lp,Tree rp)
{
p.cnt=lp.cnt+rp.cnt;
}
void add(int l,int r,int val,int &p)
{
if(!p) p=++tot;
if(l==r)
{
tree[p].cnt++;
return;
}
int mid=(l+r)>>1;
if(val<=mid) add(l,mid,val,tree[p].lp);
else add(mid+1,r,val,tree[p].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
}
void merge(int l,int r,int p1,int p2)//将 p2 合并到 p1 里面
{
// if(p10&&p20) return;
if(l==r) { tree[p1].cnt+=tree[p2].cnt; return; }
int mid=(l+r)>>1;
if(tree[p1].lp&&tree[p2].lp) merge(l,mid,tree[p1].lp,tree[p2].lp);
if(tree[p1].rp&&tree[p2].rp) merge(mid+1,r,tree[p1].rp,tree[p2].rp);
if(tree[p1].lp==0&&tree[p2].lp) tree[p1].lp=tree[p2].lp;//注意 if 顺序
if(tree[p1].rp==0&&tree[p2].rp) tree[p1].rp=tree[p2].rp;
pushup(tree[p1],tree[tree[p1].lp],tree[tree[p1].rp]);
}
int kth(int l,int r,int k,int p)
{
if(l==r) return l;
int mid=(l+r)>>1,lp=tree[p].lp,rp=tree[p].rp;
int nw=tree[lp].cnt;
if(nw>=k) return kth(l,mid,k,lp);
else return kth(mid+1,r,k-nw,rp);
}
signed main()
{
//mt19937_64 myrand(time(0));
n=read();
m=read();
for(int i=1;i<=n;i++)
{
int x=read();
p[x]=i;
add(MINN,MAXN,x,root[i]);
fa[i]=i;
}
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
int fx=find(u),fy=find(v);
if(fx==fy) continue;
fa[fy]=fx;
merge(MINN,MAXN,root[fx],root[fy]);
}
int q=read();
while(q--)
{
char op=readc();
int x=read(),y=read();
// cout<<7-q<<" "<<op<<" "<<x<<" "<<y<<" \n";
int fx=find(x);
if(op=='Q')
{
int nw=kth(MINN,MAXN,y,root[fx]);
write(((nw==MAXN)?-1:p[nw]));
putchar('\n');
continue;
}
if(op=='B')
{
int fy=find(y);
if(fx==fy) continue;
fa[fy]=fx;
merge(MINN,MAXN,root[fx],root[fy]);
}
}
return 0;
}
</details>
[P4513 小白逛公园](https://www.luogu.com.cn/problem/P4513):单点修改区间最大子段和
[P5494 【模板】线段树分裂](https://www.luogu.com.cn/problem/P5494):(权值)线段树分裂模板题
<details>
<summary>点击查看代码</summary>
```cpp
#include<bits/stdc++.h>
#define int long l
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int MINN=-10,MAXN=1e7+7;
int root[1<<20];
struct Tree{
int lp,rp,cnt;
}tree[32000005];
int tot;
void pushup(Tree &p,Tree lp,Tree rp)
{
p.cnt=lp.cnt+rp.cnt;
}
void add(int l,int r,int val,int x,int &p)
{
if(!p) p=++tot;
if(l==r)
{
tree[p].cnt+=x;
return;
}
int mid=(l+r)>>1;
if(val<=mid) add(l,mid,val,x,tree[p].lp);
else add(mid+1,r,val,x,tree[p].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
}
// 将 p2 合并到 p1 里
void merge(int l,int r,int &p1,int &p2)
{
if(!p1) p1=++tot;
if(l==r)
{
tree[p1].cnt+=tree[p2].cnt;
return;
}
int mid=(l+r)>>1;
if(tree[p1].lp&&tree[p2].lp) merge(l,mid,tree[p1].lp,tree[p2].lp);
else if(tree[p2].lp) tree[p1].lp=tree[p2].lp,tree[p2].lp=0;
if(tree[p1].rp&&tree[p2].rp) merge(mid+1,r,tree[p1].rp,tree[p2].rp);
else if(tree[p2].rp) tree[p1].rp=tree[p2].rp,tree[p2].rp=0;
pushup(tree[p1],tree[tree[p1].lp],tree[tree[p1].rp]);
pushup(tree[p2],tree[tree[p2].lp],tree[tree[p2].rp]);
}
//将 [sl,sr] 从 p2 中分离
void spilt(int l,int r,int sl,int sr,int &p1,int &p2)
{
if(sl<=l&&r<=sr)
{
p1=p2;
p2=0;
tree[p2]={0,0,0};
return;
}
if(!p1) p1=++tot;
int mid=(l+r)>>1;
if(sl<=mid) spilt(l,mid,sl,sr,tree[p1].lp,tree[p2].lp);
if(sr>mid) spilt(mid+1,r,sl,sr,tree[p1].rp,tree[p2].rp);
pushup(tree[p1],tree[tree[p1].lp],tree[tree[p1].rp]);
pushup(tree[p2],tree[tree[p2].lp],tree[tree[p2].rp]);
}
int query(int l,int r,int x,int p)
{
if(l==r) return 1;
int mid=(l+r)>>1,lp=tree[p].lp,rp=tree[p].rp;
if(x<=mid) return query(l,mid,x,lp);
else return tree[lp].cnt+query(mid+1,r,x,rp);
}
int kth(int l,int r,int k,int p)
{
if(l==r) return l;
int mid=(l+r)>>1,lp=tree[p].lp,rp=tree[p].rp;
int nw=tree[lp].cnt;
if(nw>=k) return kth(l,mid,k,lp);
else return kth(mid+1,r,k-nw,rp);
}
int n,m;
int a[1<<20];
signed main()
{
//mt19937_64 myrand(time(0));
// freopen("P5494_3.in","r",stdin);
n=read();
m=read();
int nw=1;
for(int i=1;i<=n;i++) a[i]=read(),add(MINN,MAXN,i,a[i],root[1]);
while(m--)
{
// cout<<tree[0].cnt<<"\n\n\n";
int op=read();
if(op==0)
{
int p=read(),x=read(),y=read();
nw++;
spilt(MINN,MAXN,x,y,root[nw],root[p]);
}
if(op==1)
{
int p=read(),t=read();
merge(MINN,MAXN,root[p],root[t]);
// root[t]=0;
}
if(op==2)
{
int p=read(),x=read(),q=read();
add(MINN,MAXN,q,x,root[p]);
}
if(op==3)
{
int p=read(),x=read(),y=read();
int nw=query(MINN,MAXN,y+1,root[p])-query(MINN,MAXN,x,root[p]);
write(nw);
putchar('\n');
if(nw==823) {cout<<op<<" "<<"\n\n\n";break;}
}
if(op==4)
{
int p=read(),k=read();
int nw=kth(MINN,MAXN,k,root[p]);
if(nw==MAXN||nw==MINN) nw=-1;
write(nw);
putchar('\n');
if(nw==823) {cout<<op<<" "<<"\n\n\n"; break;}
}
}
return 0;
}
/*
10 11
1 1 1 0 1 1 0 1 1 1
0 1 2 5
2 2 3 4
3 2 1 5
3 2 1 4
3 2 3 4
3 2 4 4
4 1 3
4 2 5
4 1 8
4 2 10
4 2 0
*/
//1: 1 0 0 0 0 1 0 1 1 1
//2: 0 1 1 0 1 0 0 0 0 0
//-> 0 1 1 3 1 0 0 0 0 0
// 1 2 3 4 5 6 7 8 9 10
/*
0 1 2 5
2 2 3 4
3 2 1 5 -> 6
3 2 1 4 -> 5
3 2 3 4 -> 4
3 2 4 4 -> 3
4 1 3 -> 8
4 2 5 -> 4
4 1 8 -> -1
4 2 10 -> -1
4 2 0 -> -1
*/
P3168 [CQOI2015] 任务查询系统:神仙主席树题(差分后可看作单点修改,按时间从小到大排序后分配编号,再跑主席树)(树套树也可做,第一次写的是树套树,发现没有主席树好维护写挂了不会调,于是改写主席树)
Update on 2025/2/25
P2633 Count on a tree:树上维护主席树,对根节点到这个节点路径上的权值建主席树, add(MINN,MAXN,a[p],root[p],root[fa]);,查询明天再写。
查询时运用前缀和,\(u\) 到 \(v\) 路径上主席树(查询区间第 \(k\) 小)可表示为 \(u+v-lca(u,v)-fa[lca(u,v)]\)。
感性理解一下
点击查看 P2633 代码
#include<bits/stdc++.h>
#ne int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
// int n,m,s;
const int MAXN=pow(2,31),MINN=0;
vector<int> E[1<<20];
int f[1<<20][22];
void add(int u,int v) { E[u].push_back(v); }
int n,m;
int deep[1<<20];
int a[1<<20];
int lca(int x,int y);
struct S_tree{
int root[1<<20];
int tot;
struct Tree{
int lp,rp,cnt;
}tree[100005*33];
int tmp[3][3],cnt[3];
void pushup(Tree &p,Tree lp,Tree rp)
{
p.cnt=lp.cnt+rp.cnt;
}
void add(int l,int r,int val,int &p,int lastp)
{
if(!p) p=++tot;
if(l==r)
{
tree[p].cnt=tree[lastp].cnt+1;
return;
}
int mid=(l+r)>>1;
if(val<=mid) tree[p].rp=tree[lastp].rp,add(l,mid,val,tree[p].lp,tree[lastp].lp);
else tree[p].lp=tree[lastp].lp,add(mid+1,r,val,tree[p].rp,tree[lastp].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
}
void prepare(int x,int y)
{
memset(tmp,0,sizeof(tmp));
cnt[0]=cnt[1]=2;
tmp[1][1]=root[x];
tmp[1][2]=root[y];
int nw=lca(x,y);
tmp[0][1]=root[nw];
tmp[0][2]=root[f[nw][0]];
}
int kth(int l,int r,int k)
{
if(l==r) return l;
int mid=(l+r)>>1,nw=0;
for(int i=1;i<=cnt[1];i++) nw+=tree[tree[tmp[1][i]].lp].cnt;
for(int i=1;i<=cnt[0];i++) nw-=tree[tree[tmp[0][i]].lp].cnt;
if(nw>=k)
{
for(int i=1;i<=cnt[1];i++) tmp[1][i]=tree[tmp[1][i]].lp;
for(int i=1;i<=cnt[0];i++) tmp[0][i]=tree[tmp[0][i]].lp;
return kth(l,mid,k);
}
else
{
for(int i=1;i<=cnt[1];i++) tmp[1][i]=tree[tmp[1][i]].rp;
for(int i=1;i<=cnt[0];i++) tmp[0][i]=tree[tmp[0][i]].rp;
return kth(mid+1,r,k-nw);
}
}
int query_kth(int x,int y,int k)
{
prepare(x,y);
return kth(MINN,MAXN,k);
}
}tree;
void dfs(int p,int fa)
{
tree.add(MINN,MAXN,a[p],tree.root[p],tree.root[fa]);
deep[p]=deep[fa]+1;
f[p][0]=fa;
for(int i=0;i<E[p].size();i++)
{
int to=E[p][i];
if(to==fa) continue;
dfs(to,p);
}
}
void init()
{
for(int k=1;k<=20;k++)
for(int i=1;i<=n;i++)
f[i][k]=f[f[i][k-1]][k-1];
}
int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
for(int k=20;k>=0;k--)
{
if(deep[f[x][k]]>=deep[y])
{
x=f[x][k];
}
}
if(x==y) return x;
for(int k=20;k>=0;k--)
{
if(f[x][k]!=f[y][k])
{
x=f[x][k];
y=f[y][k];
}
}
return f[x][0];
}
signed main()
{
n=read();
m=read();
for(int i=1;i<=n;i++) a[i]=read();
// root=read();
// root=1;
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y);
add(y,x);
}
dfs(1,0);
init();
int last=0;
while(m--)
{
int u=read()^last,v=read(),k=read();
last=tree.query_kth(u,v,k);
write(last);
putchar('\n');
}
// {
// int a=read(),b=read();
// write(lca(a,b));
// putchar('\n');
// }
//mt19937_64 myrand(time(0));
return 0;
}
Update on 2025/3/17
P3302 [SDOI2013] 森林
操作:动态 lca + 树上主席树(树上主席树合并)
查询与 P2633 一样,关键看合并怎么写。
每次联边 (u,v) 时比较 u 所在树与 v 所在树节点个数(大小),将小的合并进大的,暴力重构小树中的主席树。
我们还需要求 lca,可以树链剖分,每次暴力重构小树中与树链剖分有关的数组,时间复杂度优秀,为 O(siz)。
点击查看 P3302 代码
#include<bits/stdc++.h>
#ne int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}inline int readc()
{
int c=getchar();
for(;c<'A'||c>'Z';c=getchar());
return c;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,m,q;
int ROOT;
int a[1<<20];
bool FF=0;
const int MINN=0,MAXN=1e9+1;
vector<int> E[1<<20];
void aaadd(int x,int y) { E[x].push_back(y); }
struct BCJ{
int father[1<<20];
int siz[1<<20];
void init()
{
for(int i=0;i<(1<<20);i++)
{
father[i]=i;
siz[i]=1;
}
}
int find(int x)
{
if(x==father[x]) return x;
return father[x]=find(father[x]);
}
void merge(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx==fy) return;
father[fy]=fx;
siz[fx]+=siz[fy];
}
}bcj;
struct SLPF{
int f[1<<20];
int siz[1<<20];
int top[1<<20],son[1<<20],deep[1<<20];
void dfs2(int p,int tp)
{
top[p]=tp;
if(son[p]) dfs2(son[p],tp);
for(int i=0;i<E[p].size();i++)
{
int to=E[p][i];
if(to==f[p]||to==son[p]) continue;
dfs2(to,to);
}
}
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(deep[top[v]]>deep[top[u]]) swap(u,v);
u=f[top[u]];
}
return deep[u]<deep[v]?u:v;
}
}slpf;
struct S_Tree{
int root[1<<20];
int cnt[2];
int tmp[2][4];
int tot=0;
struct Tree{
int lp,rp,cnt;
}tree[15000001];
// int st[100005*101],tp;
// {
// }
void pushup(Tree &p,Tree lp,Tree rp)
{
p.cnt=lp.cnt+rp.cnt;
}
void add(int l,int r,int val,int op,int &p,int lastp)
{
// if(!p) p=NewNode();
if(!p) p=++tot;
tree[p].cnt=0;
// tree[tree[p].lp].cnt=0;
// tree[tree[p].rp].cnt=0;
if(l==r)
{
tree[p].cnt=tree[lastp].cnt+op;
return;
}
int mid=(l+r)>>1;
if(val<=mid) tree[p].rp=tree[lastp].rp,add(l,mid,val,op,tree[p].lp,tree[lastp].lp);
else tree[p].lp=tree[lastp].lp,add(mid+1,r,val,op,tree[p].rp,tree[lastp].rp);
pushup(tree[p],tree[tree[p].lp],tree[tree[p].rp]);
// cout<<"p="<<p<<" cnt="<<tree[p].cnt<<"\n";
}
void prepare(int u,int v,int lca,int fa_lca)
{
cnt[0]=cnt[1]=2;
tmp[1][0]=root[u];
tmp[1][1]=root[v];
tmp[0][0]=root[lca];
tmp[0][1]=root[fa_lca];
// cout<<u<<" "<<v<
}
int kth(int l,int r,int k)
{
// if(FF) cout<<"l="<<l<<" r="<<r<<" k="<<k<<" ";
if(l==r) return l;
int mid=(l+r)>>1,nw=0;
for(int i=0;i<cnt[1];i++) nw+=tree[tree[tmp[1][i]].lp].cnt;
for(int i=0;i<cnt[0];i++) nw-=tree[tree[tmp[0][i]].lp].cnt;
// if(FF) cout<<"nw="<<nw<<"\n";
if(nw>=k)
{
for(int i=0;i<cnt[1];i++) tmp[1][i]=tree[tmp[1][i]].lp;
for(int i=0;i<cnt[0];i++) tmp[0][i]=tree[tmp[0][i]].lp;
return kth(l,mid,k);
}
else
{
for(int i=0;i<cnt[1];i++) tmp[1][i]=tree[tmp[1][i]].rp;
for(int i=0;i<cnt[0];i++) tmp[0][i]=tree[tmp[0][i]].rp;
return kth(mid+1,r,k-nw);
}
}
}tree;
void dfs1(int p,int fa)
{
// cout<<p<<" "<<fa<<" \n";
// tree.root[p]=0;
slpf.son[p]=0;
slpf.f[p]=fa;
slpf.siz[p]=1;
// slpf.top[p]=0;
if(FF) cout<<fa<<" "<<p<<"\n";
slpf.deep[p]=slpf.deep[fa]+1;
tree.add(MINN,MAXN,a[p],1,tree.root[p],tree.root[fa]);
int maxn=-1;
for(int i=0;i<E[p].size();i++)
{
int to=E[p][i];
if(to==fa) continue;
dfs1(to,p);
slpf.siz[p]+=slpf.siz[to];
if(slpf.siz[to]>maxn)
{
maxn=slpf.siz[to];
slpf.son[p]=to;
}
}
}
signed main()
{
// freopen("a.in","r",stdin);
// mt19937_64 myrand(time(0));
int OOOOOOOOOOOOOOOOOOOOOOOOO=read();
bcj.init();
n=read();
m=read();
q=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
// ROOT=u;
aaadd(u,v);
aaadd(v,u);
int fx=bcj.find(u);
int fy=bcj.find(v);
// if(bcj.siz[fy]>bcj.siz[fx]) swap(fy,fx),swap(x,y);
bcj.father[fy]=bcj.father[fx];
bcj.siz[fx]+=bcj.siz[fy];
}
// dfs1(ROOT,0);
// slpf.dfs2(ROOT,ROOT);
for(int i=1;i<=n;i++) if(!slpf.deep[i]) dfs1(i,0),slpf.dfs2(i,i);
int lastans=0;
while(q--)
// for(int i=1;i<=1;i++)
{
char c=readc();
// cout<<c<<" ";
if(c=='Q')
{
int x=read(),y=read(),k=read();
x^=lastans;
y^=lastans;
k^=lastans;
// cout<<"q="<<20-q<<" "<<x<<" "<<y;
int lca=slpf.lca(x,y);
int fa_lca=slpf.f[lca];
// cout<<" "<<lca<<" "<<fa_lca<<" "<<k<<"\n";
// if(q==6) FF=1;
tree.prepare(x,y,lca,fa_lca);
lastans=tree.kth(MINN,MAXN,k);
// if(lastans==1000000001) FF=1;
// else FF=0;
// if(FF)cout<<"q="<<20-q<<" "<<x<<" "<<y;
// if(FF)cout<<" "<<lca<<" "<<fa_lca<<" "<<k<<"\n";
// if(FF) dfs1(lca,0);
// if(FF)tree.kth(MINN,MAXN,k);
cout<<lastans<<"\n";
}
else if(c=='L')
{
int x=read(),y=read();
x^=lastans;
y^=lastans;
// cout<<"edge: "<<x<<" "<<y<<" \n";
int fx=bcj.find(x);
int fy=bcj.find(y);
if(bcj.siz[fy]>bcj.siz[fx]) {swap(x,y);}
bcj.father[fy]=fx;
bcj.siz[fx]+=bcj.siz[fy];
aaadd(x,y);
aaadd(y,x);
dfs1(y,x);
slpf.dfs2(y,y);
}
}
return 0;
}
/*
1
20 12 20
412060525 1
!42425138 2
!67114752 3
160822495 4
201962681 5
926214957 6
!380263349 7
!733667141 8
!869039239 9
!641017702 10
154667400 11
461702107 12
! 438851950 13
176272938 14
!209229857 15
!985208975 16
762952138 17
!936593832 18
409183276 19
! 999506034 20
2 17
4 1
15 3
3 10
9 10
7 16
19 15
13 2
6 2
3 14
7 18
8 15
Q 6 17 2
Q 762952152 762952154 762952139
L 380263329 380263352
L 380263357 380263333
Q 380263356 380263359 380263348
L 641017709 641017703
L 641017716 641017700
Q 641017716 641017704 641017698
Q 380263359 380263357 380263345
L 733667140 733667136
L 733667150 733667156
L 733667145 733667142
Q 733667149 733667145 733667140
Q 67114772 67114761 67114759
Q 733667145 733667159 733667142
Q 380263359 380263356 380263351
Q 869039233 869039232 869039237
Q 380263359 380263345 380263356
Q 733667136 733667140 733667143
Q 412060537 412060516 412060519
*/
/*
762952138
380263349
641017702
380263349
733667141
67114752
733667141
380263349
869039239
380263349
733667141
412060525
985208975
*/
以下是博客签名,正文无关
本文来自博客园,作者:Wy_x,转载请在文首注明原文链接:https://www.cnblogs.com/Wy-x/p/18712098
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC-BY-NC-SA 4.0 协议)进行许可。

浙公网安备 33010602011771号