重セグメントツリーは、永続&& &&会長セグメントツリーの木することができ

重セグメントツリー

名前が示すように、それは価値のインデックスセグメントツリーの権利を確立することです。

今度は、三つの小さな問題の上記の文章を生成について考えてみましょう:

1.重量は、次のようにマークされた場合、および風雲ツリーラインということは?どのような店で
-----風雲ツリーラインは、それぞれの値が発生した回数を記録します

大きなウェイトを行うには?アレイのスペースが十分にああではないか2.
その後、-----可能な第1の離散、記録

3.最後に重みツリーラインはそれをやってするために使用される?
-----すぐに小さなk値を見つけることができます(実際には、主に会長ツリーの友人のための道を開くために)

それを見つけるためにどのように最初の小さな値k ???
とルートから下に移動
現在の値がKの値よりも大きい場合には、K- =左の値の息子、その後、彼の息子を左、右、その後、彼の息子を訪問
Kは、左の息子の現在の値よりも小さい場合値は、左の息子への直接アクセス
リーフノード、必要表されるノード番号にアクセスするまで小さいK値の
値は、範囲の間隔の発生のノード番号に格納されているので、(実際には、第1のK )K-1が出現数の前に小さな値が存在するであろう

コードはあきらめません

永続セグメントツリー

クエリの自然な範囲を変更する単一のポイントと共通のツリーライン操作は問題ではありません
が、
あれば動作範囲、それに対する変更の現在の数を尋ねる前に???

それについて考えてみよう



最も暴力的なアプローチは、ツリーラインを再開するために、各変更操作のために間違いなく、
これは明らかに劣らず、オープンスペースではありませんけど...
私たちはそれについて最適化することができます

私たちは、修正の単一のポイントを探し、操作風雲ツリーライン操作バーの前と後の違いは何です

少しピエロ、ウォッチングで間に合わせます
彼らは唯一の赤いボックスに差があることが判明し、これら2つのツリーを見て
パスちょっとは???これはそれのルートにターゲット要素の動作を変更することではありませんが、

このパスのみが変更されているので、その後、私たちはツリー全体をコピーする必要はありません、よくこのパスをコピー
スペースを大幅に低減することができる(ログレベル)

コード(ロス・バレーテンプレート

#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
*/

静的会長ツリー

間隔kが小さい/大きい値を見つけるために使用することができます

端的に言えば、それはで、つまり、上記の二つのこと一緒に私たちにある永続量のセグメントツリー

具体的な成果はステップを見て:
1.空のセグメントツリー構築
ターンの各値(変更操作として見られる)は、セグメントツリーZhekeに追加される2。

クエリ:
(現在のクエリ間隔L〜R場合)
直接の歴史とバージョンR L-1の履歴バージョンには、直接の減算は、あなたは、各出現する間隔の現在の数を取得することができます

コード(ロス・バレーテンプレート

#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));
    }
}

おすすめ

転載: www.cnblogs.com/yzhx/p/11615616.html
おすすめ