Weight segment tree can be persistent && && chairman segment tree tree

Weight segment tree

As the name suggests, it is to establish the right to a value index segment tree.

Now let's think about generating the above sentence of three small problems:

1. If the weight marked as the next, and that Fengyun tree line in what store it?
----- Fengyun tree line, record the number of times each value occurs

2. how to do big weights? Array space is not enough ah
----- can first discrete, then record

3. That the weights tree line in the end is used to doing it?
----- can quickly find small k-value (in fact, mainly in order to pave the way for Chairman tree friends)

That first small value k ??? how to find it
and move down from the root
if the current value is greater than the value of K left his son, then the son of K- = value of the left, the right and then visit his son
if K is less than the current value of the left son value, direct access to the left son
of a small k value until access to the leaf node, the node number that is represented required
(in fact, because the value is stored in the node number in the range interval occurrences, so the first k there will be a small value in front of the number k-1 appeared)

The code will not give up

Persistable segment tree

Common tree line operation with a single point of modifying the natural range of the query is not a problem
, but
before asking if the current number of changes to the operating range it ???

Think about it
.
.
.
The most violent approach is undoubtedly for each modification operation to reopen a tree line,
but ... this is clearly no less open space
that we can optimize about it

We look for a single point of modification, what's the difference before and after the operation Fengyun tree line operation bar

A little clown, make do with watching
Look at these two trees, they found that there is a difference only in the red box where
the path hey ??? This is not to modify the operation of the target element to the root of it

Since only this path has changed, then we just copy this path well, do not have to copy the entire tree
so the space can be greatly reduced (log level)

Code ( Los Valley template )

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define get getchar()
#define in inline
in int read()
{
    int x=1,t=0; char ch=get;
    while((ch<'0' || ch>'9') && ch!='-') ch=get;
    if(ch=='-') ch=get,x=-1;
    while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
    return t*x;
}
const int _=1e6+6;
int n,m,a[_],tot,root[_<<5],ls[_<<5],rs[_<<5],val[_<<5]; // ls == leftson,rs == rightson
in int build(int l,int r)
{
    int now=++tot;
    if(l==r)
    {
        ls[now]=rs[now]=0;
        val[now]=a[l];
        return now;
    }
    int mid=(l+r)>>1;
    ls[now]=build(l,mid);
    rs[now]=build(mid+1,r);
    return now;
} //初始时的线段树
in int add(int k,int l,int r,int x,int t)
{
    int now=++tot;
    if(l==r)
    {
        val[now]=t;
        ls[now]=rs[now]=0;
        return now;
    } //到了目标点,修改它
    ls[now]=ls[k],rs[now]=rs[k];
    int mid=(l+r)>>1;
    if(x<=mid) ls[now]=add(ls[now],l,mid,x,t); //若目标点在原树的左子树上,则新建左儿子
    else rs[now]=add(rs[now],mid+1,r,x,t); //若在右儿子上,同理
    return now;
} //修改并添加新路径
in int query(int k,int l,int r,int x)
{
    if(l==r) return val[k];
    int mid=(l+r)>>1;
    if(x<=mid) return query(ls[k],l,mid,x);
    else return query(rs[k],mid+1,r,x);
} //查询
int main()
{
    n=read(),m=read();
    for(re int i=1;i<=n;i++)
        a[i]=read();
    root[0]=build(1,n);
    for(re int i=1;i<=m;i++)
    {
        int v=read(),o=read();
        if(o==1)
        {
            int x=read(),y=read();
            root[i]=add(root[v],1,n,x,y);
        }
        else
        {
            int x=read();
            cout<<query(root[v],1,n,x)<<endl;
            root[i]=root[v];
        }
    }
    /*for(re int i=0;i<=10;i++)
    {
        cout<<"case #"<<i<<":    ";
        for(re int j=1;j<=n;j++)
        cout<<query(root[i],1,n,j)<<' ';
        cout<<endl;
    }//打印每个历史版本 */ 
    return 0;
}
/*
 9.30 By yzhx
*/

Static Chairman tree

Interval k can be used to find small / large value

To put it plainly, it is to us the above mentioned two things together, that is, with a persistence-weight segment tree

Specific achievements look steps:
1. an empty segment tree building
2. Each value in turn is added to the segment tree Zheke (seen as a modify operation)

Query:
(if the current query interval l ~ r)
directly to history and historical versions of version r l-1, direct subtraction, you can get the current number of the interval for each occurrence of the

Code ( Los Valley template )

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define in inline
#define get getchar()
in int read()
{
    int t=0,x=1; char ch=get;
    while((ch<'0' || ch>'9') && ch!='-') ch=get;
    if(ch=='-') ch=get,x=-1;
    while( ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
    return t*x;
}
const int _=2e5+5;
int tot,cnt,n,m,a[_],b[_],sum[_<<6],ls[_<<6],rs[_<<6],root[_];
in int build(int l,int r)
{
    int now=++cnt;
    if(l==r)
    {
        sum[now]=ls[now]=rs[now]=0;
        return now;
    }
    int mid=(l+r)>>1;
    ls[now]=build(l,mid),rs[now]=build(mid+1,r);
    return now;
} //建一颗空树
in int add(int k,int l,int r,int x)
{
    int now=++cnt;
    if(l==r)
    {
        ls[now]=rs[now]=0;
        sum[now]=sum[k]+1;
        return now;
    }
    int mid=(l+r)>>1;
    ls[now]=ls[k],rs[now]=rs[k],sum[now]=sum[k];
    if(x<=mid) ls[now]=add(ls[k],l,mid,x);
    else rs[now]=add(rs[k],mid+1,r,x);
    sum[now]=sum[rs[now]]+sum[ls[now]];
    return now;
} //加入每个元素
in int query(int k1,int k2,int l,int r,int x)
{
    if(l==r) return a[l];
    int mid=l+r>>1;
    int t=sum[ls[k2]]-sum[ls[k1]];
    if(x<=t) return query(ls[k1],ls[k2],l,mid,x);
    else return query(rs[k1],rs[k2],mid+1,r,x-t);
} //查询
int main()
{
    n=read(),m=read();
    for(re int i=1;i<=n;i++)
        b[i]=a[i]=read();
    sort(a+1,a+n+1);
    tot=unique(a+1,a+n+1)-(a+1);
    root[0]=build(1,n);
    for(re int i=1;i<=n;i++)
    {
        //  if(i<=tot) cout<<a[i]<<' ';
        int x=lower_bound(a+1,a+tot+1,b[i])-a;
        root[i]=add(root[i-1],1,tot,x);
    }
    //cout<<endl;
    for(re int i=1;i<=m;i++)
    {
        int l=read(),r=read(),k=read();
        printf("%d\n",query(root[l-1],root[r],1,tot,k));
    }
}

Guess you like

Origin www.cnblogs.com/yzhx/p/11615616.html