权值线段树/主席树专题

权值线段树

HDU1396 Minimum Inversion Number

求序列最小逆序数

权值线段树单点更新区间查询

#include<bits/stdc++.h>
using namespace std;
const int MAX=5e3+5;
int a[MAX],n;
struct P
{
    int l,r,v;
}b[MAX<<2];
void build(int rt,int l,int r)
{
    b[rt].l=l;b[rt].r=r;b[rt].v=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
}
void update(int rt,int pos)
{
    if(b[rt].l==b[rt].r) {++b[rt].v;return;}
    int mid=(b[rt].l+b[rt].r)>>1;
    if(pos<=mid) update(rt<<1,pos);
    else update(rt<<1|1,pos);
    b[rt].v=b[rt<<1].v+b[rt<<1|1].v;
}
int query(int rt,int L,int R)
{
    if(b[rt].l==L&&b[rt].r==R) return b[rt].v;
    int mid=(b[rt].l+b[rt].r)>>1;
    if(R<=mid) return query(rt<<1,L,R);
    else if(L>mid) return query(rt<<1|1,L,R);
    else return query(rt<<1,L,mid)+query(rt<<1|1,mid+1,R);
}
int main()
{
    while(~scanf("%d",&n))
    {
        int sum=0;
        build(1,1,n+1);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);++a[i];
            sum+=query(1,a[i]+1,n+1);
            update(1,a[i]);
        }
        int ans=sum;
        for(int i=n;i>0;--i)
        {
            sum=sum-(n-a[i])+(a[i]-1);
            ans=min(ans,sum);
        }
        printf("%d\n",ans);
    }
    return 0;
}

指针版动态开点,减少内存

#include<bits/stdc++.h>
using namespace std;
const int MAX=5e3+5;
int a[MAX],n,cnt;
struct P
{
    int l,r,v;
    P *ls,*rs;
}b[MAX<<1];
void build(P *rt,int l,int r)
{

    rt->l=l;rt->r=r;rt->v=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    rt->ls=&b[++cnt];
    rt->rs=&b[++cnt];
    build(rt->ls,l,mid);
    build(rt->rs,mid+1,r);
}
void update(P *rt,int pos)
{
    if(rt->l==rt->r) {++rt->v;return ;}
    int mid=(rt->l+rt->r)>>1;
    if(pos<=mid) update(rt->ls,pos);
    else update(rt->rs,pos);
    rt->v=rt->ls->v+rt->rs->v;
}
int query(P *rt,int L,int R)
{
    if(rt->l==L&&rt->r==R) return rt->v;
    int mid=(rt->l+rt->r)>>1;
    if(R<=mid) return query(rt->ls,L,R);
    else if(L>mid) return query(rt->rs,L,R);
    else return query(rt->ls,L,mid)+query(rt->rs,mid+1,R);
}
int main()
{
    while(~scanf("%d",&n))
    {
        cnt=0;
        int sum=0;
        build(b,1,n+1);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);++a[i];
            sum+=query(b,a[i]+1,n+1);
            update(b,a[i]);
        }
        int ans=sum;
        for(int i=n;i>0;--i)
        {
            sum=sum-(n-a[i])+(a[i]-1);
            ans=min(ans,sum);
        }
        printf("%d\n",ans);
    }
    return 0;
}

空间mlog(n)动态开点

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include <stack>
#include<vector>
#define half (l+r)>>1;
using namespace std;
int n,m;
const int maxn=400000;
struct hzw
{
    int sum;
    int add;
    int lc;
    int rc;  
}t[maxn];
int a[maxn],tot;
inline void update(int &s,int l,int r,int cl,int cr,int x)
{
    if (!s) s=++tot;
    t[s].sum+=(cr-cl+1)*x;
    if (l==cl&&r==cr)
    {
        t[s].add+=x;
        return ;
    }
    int mid=half;
    if (cr<=mid)     update(t[s].lc,l,mid,cl,cr,x);
    else if (cl>mid) update(t[s].rc,mid+1,r,cl,cr,x);
    else {
        update(t[s].lc,l,mid,cl,mid,x);
        update(t[s].rc,mid+1,r,mid+1,cr,x);
    }
}
inline int query(int s,int l,int r,int cl,int cr,int cnt)
{
    if (!s) return 0;
    if (l==cl&&r==cr)
    {
        return cnt*(cr-cl+1)+t[s].sum;
    }
    int mid=half;
    if (cr<=mid)     return query(t[s].lc,l,mid,cl,cr,cnt+t[s].add);
    else if (cl>mid) return query(t[s].rc,mid+1,r,cl,cr,cnt+t[s].add);
    else {
        return query(t[s].lc,l,mid,cl,mid,t[s].add+cnt)+query(t[s].rc,mid+1,r,mid+1,cr,cnt+t[s].add);
    }
}
int main() {
    int ans=0,cur;
    tot++;
    cin>>n>>m;
    int root=1; 
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for (int i=1;i<=n;++i) update(root,1,n,i,i,a[i]);
    for(int i=1,q,x,y;i<=m;i++)
    {   
        scanf("%d%d%d",&q,&x,&y);
        if(q==1)
        {   scanf("%d",&cur);
            update(root,1,n,x,y,cur);
        }
        else
        {   
            cout<<query(1,1,n,x,y,0)<<endl;
        }
    }
    return 0;
}

主席树-可持续化权值线段树

POJ2104 K-th Number

求区间第k大的元素

前缀和、动态加点、离散化

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int root[MAX],a[MAX],n,m,cnt;
struct P
{
    int l,r,v;
}b[MAX*25];
vector<int >v;
int id(int x)
{
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos)
{
    b[++cnt]=b[y];++b[cnt].v;x=cnt;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(pos<=mid) update(l,mid,b[x].l,b[y].l,pos);
    else update(mid+1,r,b[x].r,b[y].r,pos);
}
int query(int l,int r,int x,int y,int k)
{
    if(l==r) return l;
    int mid=(l+r)>>1;
    int sum=b[b[y].l].v-b[b[x].l].v;
    if(sum>=k) return query(l,mid,b[x].l,b[y].l,k);
    else return query(mid+1,r,b[x].r,b[y].r,k-sum);
}
int main()
{
    int x,y,k;
    while(~scanf("%d%d",&n,&m))
    {
        cnt=0;v.clear();
        for(int i=1;i<=n;++i) scanf("%d",&a[i]),v.push_back(a[i]);
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        for(int i=1;i<=n;++i) update(1,n,root[i],root[i-1],id(a[i]));
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&x,&y,&k);
            printf("%d\n",v[query(1,n,root[x-1],root[y],k)-1]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Nrtostp/article/details/82759703