P3521 [POI2011]ROT-Tree Rotations

P3521 [POI2011]ROT-Tree Rotations

  本题可以通过合并数据结构解决。

  权值线段树合并的时间复杂度为O(nlogn)。

证明:

   • n个节点相互独立。

   • 考虑合并节点的意义:两棵线段树在当前区间内都有值且新的树在当前区间的值相对原来两棵树的值都增加了。

   • 说明对于一个线段树区间,merge时访问到它的次数不会超过该区间的长度大小次。

   • 那么显然总访问次数的上限为 nlogn。

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int n,root,now,cnt;
 5 ll a,b,ans;
 6 int sum[4000050];
 7 int son[4000050][2];
 8 void calc_add(int &u,int l,int r)
 9 {
10     u=++cnt;    ++sum[u];
11     if(l==r)    return ;
12     int mid=(l+r)>>1;
13     if(now<=mid)    calc_add(son[u][0],l,mid);
14     else            calc_add(son[u][1],mid+1,r);
15 }
16 void merge(int &u,int v)
17 {
18     if(!u||!v)
19     {
20         u=u|v;
21         return ;
22     }
23     sum[u]+=sum[v];
24     a+=(ll)sum[son[u][0]]*sum[son[v][1]];
25     b+=(ll)sum[son[u][1]]*sum[son[v][0]];
26     merge(son[u][0],son[v][0]);
27     merge(son[u][1],son[v][1]);
28 }
29 void dfs(int &u)
30 {
31     scanf("%d",&now);
32     int ls,rs;
33     if(!now)
34     {
35         dfs(ls=0);    dfs(rs=0);
36         a=b=0;    u=ls;
37         merge(u,rs);
38         ans+=min(a,b);
39     }
40     else
41         calc_add(u,1,n);
42 }
43 int main()
44 {
45     scanf("%d",&n);
46     dfs(root);
47     printf("%lld",ans);
48     return 0;
49 }

原文地址:https://www.cnblogs.com/wyher/p/10371530.html

时间: 2024-10-09 15:38:22

P3521 [POI2011]ROT-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

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 &

线段树合并(【POI2011】ROT-Tree Rotations)

线段树合并([POI2011]ROT-Tree Rotations) 题意 现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有nn个叶子节点,满足这些权值为1-n1-n的一个排列).可以任意交换每个非叶子节点的左右孩子. 要求进行一系列交换,使得最终所有叶子节点的权值按照前序遍历序写出来,逆序对个数最少. 解法 我们对每一个叶子节点建立一颗权值线段树,然后,我们考虑将两个叶子节点上的线段树合并起来,然后我们考虑逆序对的个数. 如果我们将左儿子的线段树放在前面,则产生的逆

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链, 递归合并这些权值线段树,同时每次将相反位置数量

「Luogu P3521 [POI2011]ROT-Tree Rotations」

题目大意 给出一颗有 \(n\) 个叶节点的二叉树,且对于所有非叶节点都有两个儿子,每次操作可以交换任意节点的两个儿子,最终要使得先序遍历后叶节点的逆序对最少,输出这个最小值. 分析 考虑交换某个节点的两个儿子对最终答案的影响,交换之后对于子树内的逆序对并不会产生影响,对这颗子树树以外的逆序对也不会产生影响,所以产生的影响只有两颗子树.那么只需要考虑哪棵子树放前面更优就好了. 考虑用权值线段树来维护每个数出现的次数,考虑合并的时候同时计算出两种情况所产生的逆序对个数. 那么考虑如何快速计算左右子

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