Evanyou Blog 彩带

  题目传送门

Tree Rotation

题目描述

Byteasar the gardener is growing a rare tree called Rotatus Informatikus.

It has some interesting features:

The tree consists of straight branches, bifurcations and leaves.

The trunk stemming from the ground is also a branch.

Each branch ends with either a bifurcation or a leaf on its top end.

Exactly two branches fork out from a bifurcation at the end of a branch - the left branch and the right branch.

Each leaf of the tree is labelled with an integer from the range 1..n1..n.

The labels of leaves are unique.

With some gardening work, a so called rotation can be performed on any bifurcation, swapping the left and right branches that fork out of it.

The corona of the tree is the sequence of integers obtained by reading the leaves' labels from left to right.

Byteasar is from the old town of Byteburg and, like all true Byteburgers, praises neatness and order.

He wonders how neat can his tree become thanks to appropriate rotations.

The neatness of a tree is measured by the number of inversions in its corona, i.e. the number of pairs (i,j)(i,j), 1le i<jle n1i<jn such that a_i>a_jai>aj in the corona a_1,a_2,cdots,a_na1,a2,,an.

The original tree (on the left) with corona 3,1,23,1,2 has two inversions.

A single rotation gives a tree (on the right) with corona 1,3,21,3,2, which has only one inversion.

Each of these two trees has 5 branches.

Write a program that determines the minimum number of inversions in the corona of Byteasar's tree that can be obtained by rotations.

给一棵n(1≤n≤200000个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少。

输入输出格式

输入格式:

 

In the first line of the standard input there is a single integer nn(2le nle 200 0002n200 000) that denotes the number of leaves in Byteasar's tree.

Next, the description of the tree follows.

The tree is defined recursively:

  • if there is a leaf labelled with pp (1le ple n1pn) at the end of the trunk (i.e., the branch from which the tree stems),then the tree's description consists of a single line containing a single integer pp

  • if there is a bifurcation at the end of the trunk, then the tree's description consists of three parts:

    • the first line holds a single number 00
    • then the description of the left subtree follows (as if the left branch forking out of the bifurcation was its trunk),
    • and finally the description of the right subtree follows (as if the right branch forking out of the bifurcation was its trunk).

In tests worth at least 30% of the points it additionally holds that nle 5 000n5 000.

 

输出格式:

 

In the first and only line of the standard output a single integer is to be printed:

the minimum number of inversions in the corona of the input tree that can be obtained by a sequence of rotations.

 

输入输出样例

输入样例#1: 
3
0
0
3
1
2
输出样例#1: 
1

说明

给一棵n(1≤n≤200000个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少。


  分析:

  线段树合并的模板题。

  线段树合并是一种常用的技巧,一般是对权值线段树合并,方法也很简单,将两棵线段树上的权值相加即可,一般用于权值线段树。

  另外关于这题的答案统计,在合并的过程中只要把子节点的线段树放在左边,当前节点的线段树放在右边,然后子节点的左边与当前节点的右边相乘得到的就是不交换子节点得到的答案,子节点的右边与当前节点的左边相乘得到的就是交换子节点得到的答案。(正确性易证)

  Code:

//It is made by HolseLee on 15th Oct 2018
//Luogu.org P3521
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e7+5;
int n,tot,ls[N],rs[N],seg[N];
ll ans,ret1,ret2;

inline int read()
{
    char ch=getchar(); int num=0; bool flag=false;
    while( ch<'0' || ch>'9' ) {
        if( ch=='-' ) flag=false; ch=getchar();
    }
    while( ch>='0' && ch<='9' ) {
        num=num*10+ch-'0'; ch=getchar();
    }
    return flag ? -num : num;
}

int build(int l,int r,int x)
{    
    seg[++tot]=1;
    if( l==r ) return tot;
    int mid=(l+r)>>1;
    int rt=tot;
    if( x<=mid ) ls[rt]=build(l,mid,x); 
    else rs[rt]=build(mid+1,r,x);
    return rt;
}

int merge(int l,int r,int x,int y)
{
    if( !x || !y ) return x+y;
    if( l==r ) {
        seg[++tot]=seg[x]+seg[y];
        return tot;
    }
    int rt=++tot, mid=(l+r)>>1;
    ret1+=(ll)seg[ls[x]]*seg[rs[y]];
    ret2+=(ll)seg[rs[x]]*seg[ls[y]];
    ls[rt]=merge(l,mid,ls[x],ls[y]);
    rs[rt]=merge(mid+1,r,rs[x],rs[y]);
    seg[rt]=seg[ls[rt]]+seg[rs[rt]];
    return rt;
}

int get()
{
    int tmp=read();
    if( tmp ) return build(1,n,tmp);
    int now=merge(1,n,get(),get());
    ans+=min(ret1,ret2);
    ret1=ret2=0;
    return now;
}

int main()
{
    n=read();
    get(); printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cytus/p/9795256.html