POI2011 Tree Rotations

POI2011 Tree Rotations

给定一个n<=2e5个叶子的二叉树,可以交换每个点的左右子树。要求前序遍历叶子的逆序对最少。

由于对于当前结点x,交换左右子树,对于范围之外的逆序对个数并没有影响,所以可以进行线段树合并,合并时统计l在左边还是在右边更优。

#include <cstdio>
#include <cctype>
using namespace std;
typedef long long LL;

inline void read(int &x){
    char ch; x=0;
    for (; ch=getchar(), !isdigit(ch););
    for (x=ch-48; ch=getchar(), isdigit(ch);)
        x=(x<<3)+(x<<1)+ch-48;
}
inline void read(LL &x){
    char ch; x=0;
    for (; ch=getchar(), !isdigit(ch););
    for (x=ch-48; ch=getchar(), isdigit(ch);)
        x=(x<<3)+(x<<1)+ch-48;
}
inline LL min(LL a,LL b) { return a > b?b : a; }

const int maxn = 2e5+5;
struct node {
    int seg,ls,rs;
} a[maxn*30];
LL ANS = 0,ans1 = 0,ans2 = 0;
int n;

int cnt = 0;
void modify(int &x,int l,int r, int pos) {
    if(!x) x = ++cnt;
    a[x].seg++;
    int mid=l+r>>1;
    if(l == r) return;
    if(pos <= mid) modify(a[x].ls,l,mid,pos);
    else modify(a[x].rs,mid+1,r,pos);
}
void merge(int &l,int r) {
    if(!l || !r) { l+=r; return; }
    a[l].seg += a[r].seg;
    ans1 += (LL)a[a[l].rs].seg*a[a[r].ls].seg;
    ans2 += (LL)a[a[l].ls].seg*a[a[r].rs].seg;
    merge(a[l].ls,a[r].ls);
    merge(a[l].rs,a[r].rs);
}

void solve(int &x) {
    int t,ls,rs;
    x = 0; read(t);
    if(!t) {
        solve(ls),solve(rs);
        ans1 = ans2 = 0;
        x = ls;
        merge(x,rs);
        ANS += min(ans1,ans2);
    } else modify(x,1,n,t);
}

int main() {
    read(n);
    int t = 0;
    solve(t);
    printf("%lld\n",ANS);
    return 0;
}

原文地址:https://www.cnblogs.com/MyNameIsPc/p/9424834.html

时间: 2024-10-08 02:18:41

POI2011 Tree Rotations的相关文章

BZOJ2212: [Poi2011]Tree Rotations

2212: [Poi2011]Tree Rotations Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 391  Solved: 127[Submit][Status] Description Byteasar the gardener is growing a rare tree called Rotatus Informatikus. It has some interesting features: The tree consists o

bzoj2212 [Poi2011]Tree Rotations 线段树合并

Description 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

bzoj 2212 [Poi2011]Tree Rotations

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 ei

[BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】

题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换左右子树无关,是否交换左右子树取决于交换后 “跨越 x 左子树与右子树的逆序对” 是否会减小. 因此我们要求出两种情况下的逆序对数,使用线段树合并,对每个节点建一棵线段树,然后合并的同时就求出两种情况下的逆序对. 代码 #include <iostream> #include <cstdli

BZOJ 2212 [Poi2011]Tree Rotations(线段树合并)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2212 [题目大意] 给出一棵二叉树,每个叶节点上有一个权值,现在可以任意交换左右儿子, 使得逆序对最少,求最少的逆序对数量 [题解] 我们发现对于每个非叶节点来说,其贡献值为左右两个儿子的权值树上, 每个节点想反位置的数量和乘积,比如左儿子的权值树左节点和右儿子权值树的右节点相乘, 那么我们对于每个节点建立一颗权值线段树,仅保留非0链, 递归合并这些权值线段树,同时每次将相反位置数量

BZOJ2212 [Poi2011]Tree Rotations 线段树合并 逆序对

原文链接http://www.cnblogs.com/zhouzhendong/p/8079786.html 题目传送门 - BZOJ3286 题意概括 给一棵n(1≤n≤200000个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少. 题解 线段树合并. 博主很懒,题解不写了. 这份代码是仿照别人的写的. 代码 #include <cstring> #include <cstdio> #include <cmath> #include <al

bzoj 2212 : [Poi2011]Tree Rotations (线段树合并)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2212 思路:用线段树合并求出交换左右儿子之前之后逆序对的数量,如果数量变小则交换. 实现代码: #include<bits/stdc++.h> using namespace std; #define ll long long const int M = 4e5+10; int n,cnt,idx; ll ans,cnt1,cnt2; int v[M],l[M],r[M],root[

[POI2011]ROT-Tree Rotations 线段树合并|主席树 / 逆序对

题目[POI2011]ROT-Tree Rotations [Description] 现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有\(n\)个叶子节点,满足这些权值为\(1..n\)的一个排列).可以任意交换每个非叶子节点的左右孩子. 要求进行一系列交换,使得最终所有叶子节点的权值按照中序遍历写出来,逆序对个数最少. [Input Format] 第一行一个整数\(n\). 下面每行,一个数\(x\). 如果\(x =0\),表示这个节点非叶子节点,递归地向下读

P3521 [POI2011]ROT-Tree Rotations

P3521 [POI2011]ROT-Tree Rotations 本题可以通过合并数据结构解决. 权值线段树合并的时间复杂度为O(nlogn). 证明: • n个节点相互独立. • 考虑合并节点的意义:两棵线段树在当前区间内都有值且新的树在当前区间的值相对原来两棵树的值都增加了. • 说明对于一个线段树区间,merge时访问到它的次数不会超过该区间的长度大小次. • 那么显然总访问次数的上限为 nlogn. 1 #include<bits/stdc++.h> 2 #define ll lon