线段树

线段树

暂时没想好原理,先贴个代码,留待后续更新………………(逃…………

线段树

建树

void build(int l,int r,int x){
	tree[x].l=l;
	tree[x].r=r;
	tree[x].add=0;
	if(l==r){
		scanf("%lld",&tree[x].sum);
		return ;
	}
	int tmp=x*2;
	int mid=(l+r)/2;
	build(l,mid,tmp);
	build(mid+1,r,tmp+1);
	pushup(x);	 //如果在建树的过程中给sum赋值,记得后面要pushup
}

区间更新

当然不止区间更新,还有一个单点更新,但是你可以把单点想成一个区间嘛,这样就变成了区间更新

void update(ll l,ll r,ll c,ll x){
	if(r<tree[x].l||l>tree[x].r)
		return;
	if(l<=tree[x].l&&r>=tree[x].r){
		tree[x].add+=c;
		tree[x].sum+=c*(tree[x].r-tree[x].l+1);
		return;
	}
	if(tree[x].add)
		pushdown(x);
	ll tmp=x*2;
	update(l,r,c,tmp);	//  !!!
	update(l,r,c,tmp+1);
	pushup(x);
}

查询

ll query(ll l,ll r,ll x){
	if(r<tree[x].l||l>tree[x].r)		 //要更新的区间不在该区间上
		return 0;
	if(l<=tree[x].l&&r>=tree[x].r){	  //要更新区间包括了该区间
		return tree[x].sum;
	}
	if(tree[x].add)
		pushdown(x);
	ll tmp=x*2;
	ll mid=(tree[x].l+tree[x].r)/2;
	if(r<=mid)
		return query(l,r,tmp);
	else if(l>mid)
		return query(l,r,tmp+1);
	else{
		return query(l,mid,tmp)+query(mid+1,r,tmp+1);
	}
}

完整代码

ll n,m;
ll ans;
struct Tree{
	ll l,r;
	ll sum,add;
}tree[MAXN*4];
void pushup(ll x){
	ll tmp=2*x;
	tree[x].sum=tree[tmp].sum+tree[tmp+1].sum;
}
void pushdown(ll x){
	ll tmp=2*x;
	tree[tmp].add+=tree[x].add;
	tree[tmp+1].add+=tree[x].add;
	tree[tmp].sum+=tree[x].add*(tree[tmp].r-tree[tmp].l+1);
	tree[tmp+1].sum+=tree[x].add*(tree[tmp+1].r-tree[tmp+1].l+1);
	tree[x].add=0;
}
//建树
void build(int l,int r,int x){
	tree[x].l=l;
	tree[x].r=r;
	tree[x].add=0;
	if(l==r){
		scanf("%lld",&tree[x].sum);
		return ;
	}
	int tmp=x*2;
	int mid=(l+r)/2;
	build(l,mid,tmp);
	build(mid+1,r,tmp+1);
	pushup(x);	 //如果在建树的过程中给sum赋值,记得后面要pushup
}
//区间更新
void update(ll l,ll r,ll c,ll x){
	if(r<tree[x].l||l>tree[x].r)
		return;
	if(l<=tree[x].l&&r>=tree[x].r){
		tree[x].add+=c;
		tree[x].sum+=c*(tree[x].r-tree[x].l+1);
		return;
	}
	if(tree[x].add)
		pushdown(x);
	ll tmp=x*2;
	update(l,r,c,tmp);	//  !!!
	update(l,r,c,tmp+1);
	pushup(x);
}
//查询
ll query(ll l,ll r,ll x){
	if(r<tree[x].l||l>tree[x].r)		 //要更新的区间不在该区间上
		return 0;
	if(l<=tree[x].l&&r>=tree[x].r){	  //要更新区间包括了该区间
		return tree[x].sum;
	}
	if(tree[x].add)
		pushdown(x);
	ll tmp=x*2;
	ll mid=(tree[x].l+tree[x].r)/2;
	if(r<=mid)
		return query(l,r,tmp);
	else if(l>mid)
		return query(l,r,tmp+1);
	else{
		return query(l,mid,tmp)+query(mid+1,r,tmp+1);
	}
}

主席树

主席树又叫可持久化线段树或者函数式线段树,其实都是同一种东西
以下代码已通过 洛谷P3834,你也可以去测试一下你自己的板子

更新

void add(int &now,int last,int l,int r,int x) {
    now=++cut;
    tr[now].ans=tr[last].ans+1;
    tr[now].l=tr[last].l,tr[now].r=tr[last].r;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(x<=mid) add(tr[now].l,tr[last].l,l,mid,x);
    else add(tr[now].r,tr[last].r,mid+1,r,x);
    return ;
}

查询

int query(int L,int R,int l,int r,int x) {
    if(l==r) return l;
    int p=tr[tr[R].l].ans-tr[tr[L].l].ans;
    int mid=(l+r)>>1;
    if(p>=x) return query(tr[L].l,tr[R].l,l,mid,x);
    else return query(tr[L].r,tr[R].r,mid+1,r,x-p);
}

完整代码

#include <bits/stdc++.h>
#define MAXN 200001
using namespace std;
#define debug() cout<<"debugdebugdebug"<<endl
int root[MAXN],cut,a[MAXN],s[MAXN];
struct node {
    int l,r,ans;
} tr[MAXN*20];

void add(int &now,int last,int l,int r,int x) {
    now=++cut;
    tr[now].ans=tr[last].ans+1;
    tr[now].l=tr[last].l,tr[now].r=tr[last].r;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(x<=mid) add(tr[now].l,tr[last].l,l,mid,x);
    else add(tr[now].r,tr[last].r,mid+1,r,x);
    return ;
}

int query(int L,int R,int l,int r,int x) {
    if(l==r) return l;
    int p=tr[tr[R].l].ans-tr[tr[L].l].ans;
    int mid=(l+r)>>1;
    if(p>=x) return query(tr[L].l,tr[R].l,l,mid,x);
    else return query(tr[L].r,tr[R].r,mid+1,r,x-p);
}

int main() {
	int n,m;
	int x,y,z;
    while(scanf("%d%d",&n,&m)!=EOF) {
        cut=0;
        memset(root,0,sizeof root);
        for(int i=1; i<=n; i++){
        	cin>>s[i];
			a[i]=s[i];
		}
        sort(s+1,s+n+1);
        for(int i=1; i<=n; i++) {
            int p=lower_bound(s+1,s+n+1,a[i])-s;
            add(root[i],root[i-1],1,n,p);
        }
        while(m--) {
            cin>>x>>y>>z;
            int p=query(root[x-1],root[y],1,n,z);
            printf("%d\n",s[p]);
        }
    }
    return 0;
}
posted @ 2018-12-04 19:23  凌乱风中  阅读(100)  评论(0编辑  收藏  举报