标签:sum def tree info 线段 拷贝 alt src ffffff
https://www.luogu.com.cn/training/14535#problems
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int nodecnt;
int tree[maxn*30],ls[maxn*30],rs[maxn*30];
int root[maxn],a[maxn];
int maketree(int rt,int l,int r){//建树
rt=++nodecnt;
if(l==r){
tree[rt]=a[l];
return nodecnt;
}
int mid=(l+r)>>1;
ls[rt]=maketree(ls[rt],l,mid);
rs[rt]=maketree(rs[rt],mid+1,r);
return rt;
}
int get(int rt){//拷贝原节点信息
nodecnt++;
tree[nodecnt]=tree[rt];
ls[nodecnt]=ls[rt];
rs[nodecnt]=rs[rt];
return nodecnt;
}
int update(int rt,int l,int r,int x,int val){
rt=get(rt);
if(l==r){
tree[rt]=val;
}else{
int mid=(l+r)>>1;
if(x<=mid)ls[rt]=update(ls[rt],l,mid,x,val);
else rs[rt]=update(rs[rt],mid+1,r,x,val);
}
return rt;
}
int query(int rt,int l,int r,int x){//查询操作
if(l==r)return tree[rt];
int mid=(l+r)>>1;
if(x<=mid)return query(ls[rt],l,mid,x);
return query(rs[rt],mid+1,r,x);
}
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘) s=s*10+ch-‘0‘,ch=getchar();
return s*w;
}
int main(){
int n,m;
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
root[0]=maketree(0,1,n);//建原始版本线段树
for(int i=1;i<=m;i++){
int rt,op,x;
rt=read(),op=read(),x=read();
if(op==1){
int y;
y=read();
root[i]=update(root[rt],1,n,x,y);//构建新节点线段树的log(n)个节点
}
else{
printf("%d\n",query(root[rt],1,n,x));
root[i]=root[rt];//建立新版本,当前版本和查询版本一致
}
}
}
#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
int p;
int nodecnt;//实现动态开点
int a[maxn],b[maxn],n,m;//a是原数组,b是离散化数组
int size[maxn<<5],root[maxn],rs[maxn<<5],ls[maxn<<5];//size记录节点大小,root记录每一棵树的根,ls-->左儿子,rs-->右儿子
void build(int &rt,int l,int r){//间一棵空树
//引用,顺便修改,实现动态开点
rt=++nodecnt;
if(l==r){return;}
int mid=(l+r)>>1;
build(ls[rt],l,mid);
build(rs[rt],mid+1,r);
}
int get(int rt){//继承该节点原版本的全部信息
nodecnt++;
ls[nodecnt]=ls[rt];
rs[nodecnt]=rs[rt];
size[nodecnt]=size[rt]+1;
return nodecnt;
}
int modify(int rt,int l,int r){//通过rt(上一棵树的根节点)构建当前树
rt=get(rt);//继承
if(l==r)return rt;//返回当前节点的编号
int mid=(l+r)>>1;
if(p<=mid)ls[rt]=modify(ls[rt],l,mid);//记录下面节点返回的编号
else rs[rt]=modify(rs[rt],mid+1,r);
return rt;//返回当前节点的编号
}
int query(int u,int v,int l,int r,int k){
int ans;
int mid=(l+r)>>1;
int x=size[ls[v]]-size[ls[u]];//记录在l到r中左子树(l~mid)添加的数字的个数
if(l==r)return l;//到叶子节点,返回答案
if(x>=k)ans=query(ls[u],ls[v],l,mid,k);//大于则说明左子树添加的节点数大于k,那么区间第k小在左侧
else ans=query(rs[u],rs[v],mid+1,r,k-x);//区间第k小在右侧
return ans;
}
int main(){
int l,r,k,q,ans;
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];//离散化数组
}
sort(b+1,b+1+n);//排序
q=unique(b+1,b+n+1)-b-1;//去重
build(root[0],1,q);//构建空树
for(int i=1;i<=n;i++){
p=lower_bound(b+1,b+q+1,a[i])-b;//查找a[i]离散化后的大小(在b数组中的位置)
root[i]=modify(root[i-1],1,q);//根据第i-1棵线段树构建第i棵线段树
}
while(m--){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
int ans=query(root[l-1],root[r],1,q,k);//查询l,r中的区间k小
//和前缀和类似,从树l-1到r查询
printf("%d\n",b[ans]);//输出原数据
}
}
P3835 【模板】可持久化平衡树
(维护历史版本的修改查询,这里提供线段树做法)
调了好长时间,一直28分,后来发现,竟然可以删除不存在的节点????(大雾)-->>加判断
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=5e5+10;
int size[maxn*30];
int ls[maxn*30],rs[maxn*30],root[maxn];
int nodecnt;
int get(int rt){
++nodecnt;
ls[nodecnt]=ls[rt];
rs[nodecnt]=rs[rt];
size[nodecnt]=size[rt];
return nodecnt;
}
void add(int &rt,int l,int r,int x,int v){
if(rt!=0)rt=get(rt);
else if(rt==0)rt=++nodecnt;
size[rt]+=v;
if(l==r){
if(size[rt]<0)size[rt]=0;
return;
}
int mid=(l+r)>>1;
if(x<=mid)add(ls[rt],l,mid,x,v);
else add(rs[rt],mid+1,r,x,v);
size[rt]=size[ls[rt]]+size[rs[rt]];
}
int getnum(int rt,int l,int r,int x){
if(size[rt]==0||x>r){
return size[rt];
}
int mid=(l+r)>>1;
if(x<=mid)return getnum(ls[rt],l,mid,x);
return size[ls[rt]]+getnum(rs[rt],mid+1,r,x);
}
int getk(int rt,int l,int r,int k){
if(l==r)return l;
int mid=(l+r)>>1;
if(size[ls[rt]]>=k)return getk(ls[rt],l,mid,k);
return getk(rs[rt],mid+1,r,k-size[ls[rt]]);
}
signed main(){
int n;
scanf("%lld",&n);
root[0]=++nodecnt;
for(int i=1;i<=n;i++){
int rt,op,x;
scanf("%lld%lld%lld",&rt,&op,&x);
root[i]=root[rt];
if(op==1){
add(root[i],-1e9,1e9+1,x,1);
}
if(op==2){
add(root[i],-1e9,1e9+1,x,-1);
}
if(op==3){
printf("%lld\n",getnum(root[i],-1e9,1e9+1,x)+1);
}
if(op==4){
printf("%lld\n",getk(root[i],-1e9,1e9+1,x));
}
if(op==5){
int ans=getnum(root[i],-1e9,1e9+1,x);
if(ans==0)printf("%d\n",-0x7fffffff);
else printf("%lld\n",getk(root[i],-1e9,1e9+1,ans));
}
if(op==6){
int ans=getk(root[i],-1e9,1e9+1, getnum(root[i],-1e9,1e9+1,x +1)+1);
if(ans==1e9+1)printf("%d\n",0x7fffffff);
else printf("%lld\n",ans);
}
}
}
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int nodecnt;
struct node{
int v,op,x;
}temp[maxn];
int tmp[maxn],tail;
int rs[maxn*32],ls[maxn*32],size[maxn*32],root[maxn];
int n;
void build(int &curr, int l, int r) {
curr = ++nodecnt;
if (l == r) return;
int mid = (l + r) >> 1;
build(ls[curr], l, mid);
build(rs[curr], mid + 1, r);
}
int get(int rt){
nodecnt++;
ls[nodecnt]=ls[rt];
rs[nodecnt]=rs[rt];
size[nodecnt]=size[rt];
return nodecnt;
}
void add(int &rt,int l,int r,int x,int v){
rt=get(rt);
if(l==r){
size[rt]+=v;
if(size[rt]<0)size[rt]=0;
return;
}
int mid=(l+r)>>1;
if(x<=mid)add(ls[rt],l,mid,x,v);
else add(rs[rt],mid+1,r,x,v);
size[rt]=size[ls[rt]]+size[rs[rt]];
}
int opuerysum(int rt,int l,int r,int x){
if(x<l)return 0;
if(x>=r)return size[rt];
int mid=(l+r)>>1;
return opuerysum(ls[rt],l,mid,x)+opuerysum(rs[rt],mid+1,r,x);
}
int opuerykth(int rt,int l,int r,int k){
if(l==r)return l;
int mid=(l+r)>>1;
if(k<=size[ls[rt]])return opuerykth(ls[rt],l,mid,k);
else return opuerykth(rs[rt],mid+1,r,k-size[ls[rt]]);
}
int opuerypre(int v,int x){
int ans=opuerysum(root[v],1,tail,x-1);
if(!ans)return -2147483647;
else return tmp[opuerykth(root[v],1,tail,ans)];
}
int opuerysucc(int v,int x){
int ans=opuerysum(root[v],1,tail,x);
if(ans>=size[root[v]])return 2147483647;
else return tmp[opuerykth(root[v],1,tail,ans+1)];
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&temp[i].v,&temp[i].op,&temp[i].x);
if(temp[i].op!=4){
tmp[++tail]=temp[i].x;
}
}
sort(tmp+1,tmp+tail+1);
tail=unique(tmp+1,tmp+tail+1)-(tmp+1);
build(root[0],1,tail);
for(int i=1;i<=n;i++){
int v=temp[i].v,op=temp[i].op,x=temp[i].x;
if(op!=4){x=lower_bound(tmp+1,tmp+tail+1,x)-tmp;}
root[i]=root[v];
if(op==1){
add(root[i],1,tail,x,1);
}
if(op==2){
add(root[i],1,tail,x,-1);
}
if(op==3){
printf("%d\n",opuerysum(root[i],1,tail,x-1)+1);
}
if(op==4){
printf("%d\n",tmp[opuerykth(root[i],1,tail,x)]);
}
if(op==5){
printf("%d\n",opuerypre(i,x));
}
if(op==6){
printf("%d\n",opuerysucc(i,x));
}
}
}
#include<bits/stdc++.h>
using namespace std;
const int N=6e5+10;
int nodecnt;
int tree[N*24][2],latest[N*24];
int s[N],root[N],n,m;
void get(int rt,int last){
tree[rt][1]=tree[last][1];
tree[rt][0]=tree[last][0];
latest[rt]=latest[last];
}
void insert(int rt,int last,int i,int k){
get(rt,last);
if(k<0){
latest[rt]=i;
return;
}
bool rel=s[i]>>k&1;
tree[rt][rel]=++nodecnt;
insert(tree[rt][rel],tree[last][rel],i,k-1);
latest[rt]=max(latest[tree[rt][0]],latest[tree[rt][1]]);
}
int ask(int rt,int val,int k,int lim){
if(k<0)return s[latest[rt]]^val;
int rel=val>>k&1;
if(latest[tree[rt][rel^1]]>=lim)
return ask(tree[rt][rel^1],val,k-1,lim);
else
return ask(tree[rt][rel],val,k-1,lim);
}
int main(){
scanf("%d%d",&n,&m);
latest[0]=-1;
root[0]=++nodecnt;
insert(root[0],0,0,23);
for(int i=1;i<=n;i++){
int x;scanf("%d",&x);
s[i]=s[i-1]^x;
root[i]=++nodecnt;
insert(root[i],root[i-1],i,23);
}
for(int i=1;i<=m;i++){
char op;
scanf(" %c",&op);
if(op==‘A‘){
int x;scanf("%d",&x);
root[++n]=++nodecnt;
s[n]=s[n-1]^x;
insert(root[n],root[n-1],n,23);
}
else{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",ask(root[r-1],x^s[n],23,l-1));
}
}
}
可持久化数组维护可持久化并查集??
#include<bits/stdc++.h>
using namespace std;
const int maxn=200050;
int n,m,nodecnt;
int dep[maxn*30],fa[maxn*30],root[maxn],rs[maxn*30],ls[maxn*30];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘) s=s*10+ch-‘0‘,ch=getchar();
return s*w;
}
void build(int &rt,int l,int r){
if(!rt)rt=++nodecnt;
if(l==r){fa[rt]=l;return;}
int mid=(l+r)>>1;
build(ls[rt],l,mid);build(rs[rt],mid+1,r);
}
void update(int &rt,int pre,int l,int r,int x,int y){
rt=++nodecnt;
if(l==r){
dep[rt]=dep[pre];
fa[rt]=y;
return;
}
ls[rt]=ls[pre],rs[rt]=rs[pre];
int mid=(l+r)>>1;
if(x<=mid)update(ls[rt],ls[pre],l,mid,x,y);
else update(rs[rt],rs[pre],mid+1,r,x,y);
}
int query(int rt,int l,int r,int x){
if(l==r)return rt;
int mid=(l+r)>>1;
if(x<=mid)return query(ls[rt],l,mid,x);
else return query(rs[rt],mid+1,r,x);
}
void add(int rt,int l,int r,int x){
if(l==r){dep[rt]++;return;}
int mid=(l+r)>>1;
if(x<=mid)add(ls[rt],l,mid,x);
else add(rs[rt],mid+1,r,x);
}
int find_root(int rt,int now){
int nowx=query(rt,1,n,now);
if(fa[nowx]==now)return nowx;
return find_root(rt,fa[nowx]);
}
int main(){
n=read(),m=read();
build(root[0],1,n);
for(int i=1;i<=m;i++){
int op;
op=read();
if(op==1){
root[i]=root[i-1];
int x=read(),y=read();
int fx=find_root(root[i],x),fy=find_root(root[i],y);
if(fa[fx]==fa[fy])continue;
if(dep[fx]>dep[fy])swap(fx,fy);
update(root[i],root[i-1],1,n,fa[fx],fa[fy]);
if(dep[fx]+1>dep[fy])add(root[i],1,n,fa[fy]);
}
if(op==2){
int kx=read();
root[i]=root[kx];
}
if(op==3){
root[i]=root[i-1];
int x=read(),y=read();
int fx=find_root(root[i],x),fy=find_root(root[i],y);
if(fa[fx]==fa[fy])puts("1");
else puts("0");
}
}
}
标签:sum def tree info 线段 拷贝 alt src ffffff
原文地址:https://www.cnblogs.com/soda-ma/p/13358503.html