問題のロス・ソリューションバレーP3521 [[POI2011] ROT-ツリーローテーション]

バイナリツリーを考えると、リーフノードは、値が前葉の先行順走査が起こっ逆にするように、息子のノードの動作を中心に、数回交換することができるしています。

ツリーノードを考えてみましょ生成する逆に噴火:

①左のサブツリーでのみ生産。

②右のサブツリーでのみ生産。

CROSSは、③左部分木と右のサブツリーを生成します。

そのため、二分木の性質上、これだけ①②両方のケースを解決するための再帰は、ちょうど③状況を考えます。

記録情報に重みツリーラインでは、セグメントツリーで答えをカウントするマージ。

具体的な実装の詳細は、コードを確認してください。

開くことを忘れないでください\(ロング\ロング\)

\(コード:\)

#include<bits/stdc++.h>
#define maxn 10000010
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,root,tree_cnt;
ll s1,s2,ans;
bool vis[maxn];
int ls[maxn],rs[maxn],rt[maxn];
ll siz[maxn];
void pushup(int cur)
{
    siz[cur]=siz[ls[cur]]+siz[rs[cur]];
}
void modify(int L,int R,int pos,int &cur)
{
    if(!cur) cur=++tree_cnt;
    if(L==R)
    {
        siz[cur]++;
        return;
    }
    int mid=(L+R)>>1;
    if(pos<=mid) modify(L,mid,pos,ls[cur]);
    if(pos>mid) modify(mid+1,R,pos,rs[cur]);
    pushup(cur);
}
int merge(int x,int y)
{
    if(!x||!y) return x+y;
    s1+=siz[ls[x]]*siz[rs[y]];
    s2+=siz[ls[y]]*siz[rs[x]];
    ls[x]=merge(ls[x],ls[y]);
    rs[x]=merge(rs[x],rs[y]);
    pushup(x);
    return x;
}
void dfs(int &x)
{
    int val;
    read(val);
    x=++tree_cnt;
    if(!val) dfs(ls[x]),dfs(rs[x]);
    else vis[x]=true,modify(1,n,val,rt[x]);
}
void work(int x)
{
    if(vis[x]) return;
    work(ls[x]),work(rs[x]),s1=s2=0;
    rt[x]=merge(rt[ls[x]],rt[rs[x]]);
    ans+=min(s1,s2);
}
int main()
{
    read(n);
    dfs(root);
    work(root);
    printf("%lld\n",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/lhm-/p/12229829.html