首页 > 其他分享 >P3521 [POI2011]ROT-Tree Rotations

P3521 [POI2011]ROT-Tree Rotations

时间:2022-11-05 16:56:34浏览次数:94  
标签:cnt 右子 int tr POI2011 Tree cnt2 cnt1 ROT

P3521 [POI2011]ROT-Tree Rotations

分析

我们看操作,我们可以将任意一个节点的左右子树交换。

则,我们是改变的一段序列的顺序。

这里类似于的归并排序求逆序对的过程。对于某一个节点,我们在考虑交换与否左右子树会产生的最少新逆序对是多少时,只与左右子树中的数字有关,而与其数字的具体的相对关系无关了。

例如,某节点的左子树为1,4,右子树3,2,其实右子树的3,2我们根本不关心,我们只在乎其中有哪些数字,左子树1,4,右子树2,3。则不交换产生的新的逆序对为2,交换了之后,也是2

我们直接从叶节点上升过程中,维护一个权值线段树,其中维护区间内有的值的数量和,直接进行线段树合并。

但是合并过程中,我们需要计算,不交换时产生的新的逆序对ans1交换时产生的新的逆序对ans2。在合并过程中,我们需要维护两个值cnt1/2,为对于当前区间[l,r]而言,左/右子树有多少个点在该区间前,即为左/右子树在[1,l-1]有多少个点。

落实到具体的合并操作中即为。

  1. 某个区间只有左子树有,而右子树没有,则ans1+=tr[u].cnt*cnt2
  2. 同理,某个区间只有右子树有,而左子树没有,则ans2+=tr[v].cnt*cnt1
  3. 接下来到叶节点后,我们直接两个都加,ans2+=tr[v].cnt*cnt1ans1+=tr[u].cnt*cnt2

其中有个小错误,坑了我一手。就是我们合并的时候,通常是直接将第二个线段树合并到第一个线段树上。但是这样会影响我们的参数传递,因为有时左子树已经变了。可能说的不是太清楚,直接看代码。

int merge(int u,int v,int l,int r,int cnt1,int cnt2)
{
    // cout<<l<<" "<<r<<" "<<cnt1<<" "<<cnt2<<endl;
    if(!u)
    {
        ans2 += 1ll*tr[v].cnt*cnt1;
        return v;
    }
    if(!v)
    {
        ans1 += 1ll*tr[u].cnt*cnt2;
        return u;
    }
    if(l==r)
    {
        ans1 += 1ll*tr[u].cnt*cnt2;ans2 += 1ll*tr[v].cnt*cnt1;
        tr[u].cnt += tr[v].cnt;
        return u;
    }
    int mid = l + r >> 1;
    tr[u].r = merge(tr[u].r,tr[v].r,mid+1,r,cnt1 + tr[tr[u].l].cnt,cnt2 + tr[tr[v].l].cnt);//就是这里,如果跟下面的反过来的话,则传入的参数就错了
    tr[u].l = merge(tr[u].l,tr[v].l,l,mid,cnt1,cnt2);
    pushup(u);
    return u;
}

AC_code

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
using ll = long long;
const int N = 2e5 + 10;

struct Node
{
    int l,r;
    int cnt;
}tr[N*30];
int n,idx,cnt;
ll ans,ans1,ans2;
int root[N*2];

void pushup(int u)
{
    tr[u].cnt = tr[tr[u].l].cnt + tr[tr[u].r].cnt;
}

void modify(int &u,int l,int r,int x)
{
    if(!u) u = ++idx;
    if(l==r)
    {
        tr[u].cnt ++;
        return ;
    }
    int mid = l + r >> 1;
    if(x<=mid) modify(tr[u].l,l,mid,x);
    else modify(tr[u].r,mid+1,r,x);
    pushup(u);
}

int merge(int u,int v,int l,int r,int cnt1,int cnt2)
{
    // cout<<l<<" "<<r<<" "<<cnt1<<" "<<cnt2<<endl;
    if(!u)
    {
        ans2 += 1ll*tr[v].cnt*cnt1;
        return v;
    }
    if(!v)
    {
        ans1 += 1ll*tr[u].cnt*cnt2;
        return u;
    }
    if(l==r)
    {
        ans1 += 1ll*tr[u].cnt*cnt2;ans2 += 1ll*tr[v].cnt*cnt1;
        tr[u].cnt += tr[v].cnt;
        return u;
    }
    int mid = l + r >> 1;
    tr[u].r = merge(tr[u].r,tr[v].r,mid+1,r,cnt1 + tr[tr[u].l].cnt,cnt2 + tr[tr[v].l].cnt);
    tr[u].l = merge(tr[u].l,tr[v].l,l,mid,cnt1,cnt2);
    pushup(u);
    return u;
}

void dfs(int u)
{
    int x;cin>>x;
    if(!x) 
    {
        int l = ++cnt;dfs(l);
        int r = ++cnt;dfs(r);
        ans1 = 0,ans2 = 0;
        root[u] = merge(root[l],root[r],1,n,0,0);
        // cout<<ans1<<" "<<ans2<<'\n';
        ans += min(ans1,ans2);
    }
    else modify(root[u],1,n,x);
}

int main()
{
    ios;
    cin>>n;
    cnt = 1;
    dfs(cnt);
    cout<<ans<<'\n';
    return 0;
}

标签:cnt,右子,int,tr,POI2011,Tree,cnt2,cnt1,ROT
From: https://www.cnblogs.com/aitejiu/p/16860556.html

相关文章

  • C# tree view节点解析数据+model、DAL、TOOl
    EnginneModel.csnamespaceWindowsFormsApp3{publicclassEnginneModel{publicstringparamsName{get;set;}publicstringparamsT......
  • Google protoBuf
    前言:最近app要做用户行为统计埋点,对数据进行序列化和反序列化实用Google提供的protoBuf,这里也简单的介绍一下protobuf已经更新到3.2.0:查看blog下面资源包依赖:Win7+64位,and......
  • L - Fenwick Tree Gym - 103861L(打表,树状数组)
    题意:一开始数组的每个数都是零对于每次操作:可以对一个数加上一个实数在加上实数的同时,对应的i+lowbit(i)一直到<=n都会加上这个实数不同操作可以加上不同的实......
  • 如何在proto3中用上golang对应的interface{}类型
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯首先,我希望所有golang中用于http请求响应的结构,都使用proto......
  • Python xml 文件解析操作之 ElementTree 模块
    首先我们了解下XML格式Element类型是一种灵活的容器对象,用于在内存中存储结构化数据。每个element对象都具有以下属性:1.tag标签:string对象,表示数据代表的种类。......
  • CF715C Digit Tree
    妙,套,但是毒瘤。考虑\(gcd(M,10)=1\)有什么用。即\(10\)可以求\(\%M\)意义的逆元。这启示我们用\(\%M\)来做。发现数据范围特别大,记二维东西是不可能的。所以......
  • 你没见过的protected private修饰关系
    通常我们都见过publicprivateprotected以及internal,就含义来说比较容易总结public  1谁都可见private  2谁都不见除了自己protected 3你继承我否侧不......
  • el-tree只展示前三个节点数据
    后端也返回了第四等级,但是不想让他展示,可以这样解决只展示前三等级//获取room树getRoomTreeList(){getRoomTree().then((res)=>{//只获取到......
  • 二次封装 Vue-Treeselect 组件
    场景开发中多个地方都需要用到vue-treeselect组件,于是想二次封装成SelectTree组件便于使用。需求1:自定义选项样式插槽option-labelSelectTree组件预留插槽`diy-......
  • LeetCode_Stack_589. N-ary Tree Preorder Traversal N 叉树的前序遍历【栈,迭代】【简
    目录​​一,题目描述​​​​英文描述​​​​中文描述​​​​示例与说明​​​​二,解题思路​​​​三,AC代码​​​​C++​​​​Java​​​​四,解题过程​​​​第一博​......