#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 200010 using namespace std; int n,m,cnt; struct Tree { int l,r,sum; }T[MAXN*60]; int rank[MAXN],root[MAXN]; struct data { int val,ind; bool operator < (const data &a) const { return val<a.val; } }a[MAXN]; void insert(int &num,int &x,int l,int r) { T[cnt++]=T[x]; x=cnt-1; T[x].sum++; if(l==r) return; int mid=(l+r)/2; if(num<=mid) insert(num,T[x].l,l,mid); else insert(num,T[x].r,mid+1,r); } int query(int i,int j,int k,int l,int r) { if(l==r) return l; int t=T[T[j].l].sum-T[T[i].l].sum; int mid=(r+l)/2; if(k<=t) return query(T[i].l,T[j].l,k,l,mid); else return query(T[i].r,T[j].r,k-t,mid+1,r); } int main() { T[0].l=T[0].r=T[0].sum=root[0]=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i].val); a[i].ind=i; } sort(a+1,a+n+1); for(int i=1;i<=n;i++) { rank[a[i].ind]=i; } cnt=1; for(int i=1;i<=n;i++) { root[i]=root[i-1]; insert(rank[i],root[i],1,n); } while(m--) { int i,j,k; scanf("%d%d%d",&i,&j,&k); printf("%d ",a[query(root[i-1],root[j],k,1,n)].val); } }
第K小没什么说的(其实是我还不太会)
下面是可持久化数组的代码
题目大意:对于一个数组,修改一个值或查询某版本下某位的值(查询也算一个版本)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> using namespace std; struct Tree { int ls,rs; int val; }T[1000010*60]; int cnt; int a[1000010]; int root[1000010]; void build(int l,int r) { if(l==r) {T[++cnt].val=a[l];return;} int mid=(l+r)/2; build(l,mid); int l1=cnt; build(mid+1,r); int r1=cnt; T[++cnt].ls=l1;T[cnt].rs=r1; } /*void check(int x,int l,int r) { if(l>r) return; if(l==r) {printf("%d ",T[x].val);return;} int mid=(l+r)/2; check(T[x].ls,l,mid); check(T[x].rs,mid+1,r); return; }这里是判断建树是否正确*/ void ask(int p,int x,int l,int r) { if(l>r) return; if(l==r) {printf("%d ",T[p].val);return;} int mid=(l+r)/2; if(x>mid) ask(T[p].rs,x,mid+1,r); else ask(T[p].ls,x,l,mid); } void change(int p,int x,int y,int l,int r) { if(l>r) return; T[++cnt]=T[p]; if(l==r) {T[cnt].val=y;return;} int mid=(l+r)/2; if(x>mid) {T[cnt].rs=cnt+1;change(T[p].rs,x,y,mid+1,r);} else {T[cnt].ls=cnt+1;change(T[p].ls,x,y,l,mid);} } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n); root[0]=cnt; for(int i=1;i<=m;i++) { root[i]=cnt+1; int a,b; scanf("%d%d",&a,&b); if(b==1) { int c,d; scanf("%d%d",&c,&d); change(root[a],c,d,1,n); } else { cnt++; int c; scanf("%d",&c); T[root[i]]=T[root[a]]; ask(root[i],c,1,n); } } }
带回溯线段树
回溯是指当前版本与k前相同(两次回溯一个版本相当于不回溯,但版本号加了二,再变成上一个版本需要回溯3个版本)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; struct node { int l,r,ls,rs; int val,tag; }T[60*250010]; int A[100010]; int root[100010]; int cnt=0,n,m; void build(int l,int r) { if(l==r) {T[++cnt].val=A[l];T[cnt].l=l;T[cnt].r=r;return;} int mid=(l+r)/2,tmp; build(l,mid); tmp=cnt; build(mid+1,r); T[++cnt].ls=tmp; T[cnt].rs=cnt-1; T[cnt].l=l;T[cnt].r=r; T[cnt].val=T[cnt-1].val+T[tmp].val; } void pushdown(int id) { if(id) { T[T[id].ls].tag+=T[id].tag; T[T[id].rs].tag+=T[id].tag; T[id].val=T[T[id].ls].tag*(T[T[id].ls].r-T[T[id].ls].l)+T[T[id].ls].val; T[id].val+=T[T[id].rs].tag*(T[T[id].rs].r-T[T[id].rs].l)+T[T[id].rs].val; T[id].tag=0; } return; } void change(int id,int v,int l,int r) { T[++cnt]=T[id]; if(T[cnt].r==r&&T[cnt].l==l) {T[cnt].tag+=v;return;} pushdown(cnt); int tmp=cnt; int mid=(T[id].l+T[id].r)/2; if(mid>=l) {T[tmp].ls=cnt+1;change(T[id].ls,v,l,min(mid,r));} if(mid<r) {T[tmp].rs=cnt+1;change(T[id].rs,v,max(mid+1,l),r);} return; } int query(int id,int l,int r) { if(T[id].r==r&&T[id].l==l) return T[id].val+T[id].tag*(r-l+1); pushdown(id); int tmp=0,mid=(T[id].l+T[id].r)/2; if(mid>=l) tmp+=query(T[id].ls,l,min(mid,r)); if(mid<r) tmp+=query(T[id].rs,max(mid+1,l),r); return tmp; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&A[i]); } build(1,n); root[0]=cnt; int num=0; for(int i=1;i<=m;i++) { int opt; scanf("%d",&opt); if(opt==1)//区间加 { root[++num]=cnt+1; int v,l,r;scanf("%d%d%d",&l,&r,&v); change(root[num-1],v,l,r); } if(opt==2)//区间查询 { int l,r;scanf("%d%d",&l,&r); printf("%d ",query(root[num],l,r)); } if(opt==3)//回溯 { int k; scanf("%d ",&k); root[++num]=cnt+1; T[++cnt]=T[root[max(0,num-1-k)]]; } } }