首页 > 其他分享 >洛谷题单指南-线段树的进阶用法-P3157 [CQOI2011] 动态逆序对

洛谷题单指南-线段树的进阶用法-P3157 [CQOI2011] 动态逆序对

时间:2025-01-10 10:54:52浏览次数:1  
标签:return 进阶 int 洛谷题 线段 tr root 逆序

原题链接:https://www.luogu.com.cn/problem/P3157

题意解读:长度为n的序列,序列是1~n的排列,一共m个删除操作,每一个删除之前输出逆序对。

解题思路:

要计算静态的逆序对,可以通过树状数组、权值线段树等方式,时间复杂度都是O(nlogn)

要计算动态的逆序对,算上每一次删除,暴力做法需要O(mnlogn),需要优化

如果能知道删除的元素对逆序对的贡献,问题就好办了

要知道某个元素对逆序对的贡献,也就是要知道该元素前面有多个比小大,后面有多少比它小,显然是一个区间查询元素个数的问题

可以考虑建立n+1棵权值线段树,根节点为root[],第root[i]棵线段树维护序列a[1]~a[i]

那么要查询a[x]前面有多少个元素比它大,后面有多少个元素比它小,借助于前缀和思路

前面有多少个元素比它大:可以在root[x-1]的线段树中查询

后面有多少个元素比它小:可以在root[n]的线段树查询 - root[x-1]的线段树查询

如果要删除元素,比如删除a[x],则需要更新root[x]~root[n]所有线段树,这一步是需要优化,容易想到用树状数组套线段树来优化。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;

struct Node
{
    int L, R;
    int cnt;
} tr[N * 800];
int root[N], idx;
int pos[N]; //记录元素的位置
int n, m;
long long ans;

int lowbit(int x)
{
    return x & -x;
}

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

//更新根为u的线段树v值加o
int update(int u, int l, int r, int v, int o)
{
    if(!u) u = ++idx;
    if(l == r)
    {
        tr[u].cnt += o;
        return u;
    }
    int mid = l + r >> 1;
    if(v <= mid) tr[u].L = update(tr[u].L, l, mid, v, o);
    else tr[u].R = update(tr[u].R, mid + 1, r, v, o);
    pushup(u);
    return u;
}

//在根为u的线段树中查询值在lv~rv范围的数量
int query(int u, int l, int r, int lv, int rv)
{
    if(lv > rv) return 0;
    if(l >= lv && r <= rv) return tr[u].cnt;
    else if(l > rv || r < lv) return 0;
    else
    {
        int mid = l + r >> 1;
        return query(tr[u].L, l, mid, lv, rv) + query(tr[u].R, mid + 1, r, lv, rv);
    }
}

//利用树状数组更新root[pos]~root[n]线段树的v值数量,增加o
void add(int pos, int v, int o)
{
    for(int i = pos; i <= n; i += lowbit(i))
    {
        root[i] = update(root[i], 1, n, v, o);
    }
}

//利用树状数组查询root[1]~root[pos]线段树中值在lv~rv范围的数量
int find(int pos, int lv, int rv)
{
    if(lv > rv) return 0;
    int res = 0;
    for(int i = pos; i; i -= lowbit(i))
    {
        res += query(root[i], 1, n, lv, rv);
    }
    return res;
}

int main()
{
    cin >> n >> m;
    int x;
    for(int i = 1; i <= n; i++)
    {
        cin >> x;
        pos[x] = i;
        //x对逆序对的贡献是前面比x大的元素个数
        ans += find(i - 1, x + 1, n);
        add(i, x, 1);
    }
    while(m--)
    {
        cin >> x;
        cout << ans << endl;
        //删除x则减去x对逆序对的贡献,即减去x前面比x大的元素个数以及x后面比x小的元素个数
        ans -= find(pos[x] - 1, x + 1, n) + find(n, 1, x - 1) - find(pos[x], 1, x - 1);
        add(pos[x], x, -1);
    }
    return 0;
}

 

标签:return,进阶,int,洛谷题,线段,tr,root,逆序
From: https://www.cnblogs.com/jcwy/p/18658017

相关文章

  • Stable Diffusion超详细教程!从0-1入门到进阶
    一、本地部署StableDiffusion(全套教程文末领取哈)前言目前市面上比较权威,并能用于工作中的AI绘画软件其实就两款。一个叫Midjourney(简称MJ),另一个叫Stable-Diffusion(简称SD)。MJ需要付费使用,而SD开源免费,但是上手难度和学习成本略大,并且非常吃电脑配置(显卡、内存)。E和Mid......
  • Spring Bean生命周期管理:高手进阶的必修课
    SpringBean的生命周期就像一颗种子的成长过程,经历了从播种到发芽、成长、开花、结果,最终凋零的各个阶段。播种阶段(Bean定义与配置):就像农民将种子播撒在土壤中,为种子的生长做好准备。在Spring中,这是Bean定义的阶段,通过XML配置、注解或Java代码等方式,将Bean的定义信息注册到......
  • 学习笔记:C#高级进阶语法——委托(Delegate)
    四、委托4.1、什么是委托,委托的本质是什么呢?​ 1、形似一个方法,用delegate修饰符修饰。所谓委托,ILSpy反编译识别底层----生成一个一个的类。如果定义在class外部:独立生成一个类,如果定义在class内部,生成了一个类中类:包含一个2、所以委托的本质:就是一个类。4.2、委托的实例化,......
  • Flutter进阶(5):EventBus全局事件总线
    一、EventBus的基本概念FlutterEventBus是一种用于在Flutter应用程序中实现组件间通信的事件总线机制。可以用于在应用程序中实现各个组件之间的通信。它基于发布/订阅模式,允许组件订阅感兴趣的事件,并在事件发生时接收通知。二、FlutterEventBus的工作原理FlutterEventBu......
  • 【AIGC-ChatGPT进阶提示词指令】职场老油条的生存智慧:化解办公室困境的艺术
    引言在现代职场中,每个人都可能遇到各种挑战和困境。从项目管理的突发变更,到薪资谈判的微妙博弈,再到功劳归属的争议,这些都考验着职场人的智慧和情商。本文将通过实际案例,深入剖析职场常见困境的应对之道,助你在职场中游刃有余。最近比较忙,可能更新不及时,这两天忙完就恢复......
  • 【AIGC-ChatGPT进阶提示词指令】解析职场人群的心理密码
    今天逛某瓣,发现有人分享了一个【人生四季照片】,挺有意思的,然后就结合咱们的工作,想着能不能把【职业也进行四季的具象化】,所以就有了这篇文章。引言在当代职场中,每个专业领域都如同一个独特的小宇宙,塑造着从业者特定的思维方式、行为模式和情感体验。本文将深入剖析金融投......
  • 【AIGC-ChatGPT进阶提示词指令】AI美食助手的设计与实现:Lisp风格系统提示词分析
    引言在人工智能助手的应用领域中,美食烹饪是一个既专业又贴近生活的方向。本文将详细分析一个基于Lisp风格编写的美食助手系统提示词,探讨其结构设计、功能实现以及实际应用效果。提出你的菜系,为你分析,并生成图片卡片提示词在最下方效果图系统架构设计核心角色定......
  • AcWing算法基础课打卡 | 788 逆序对的数量
    学习C++从娃娃抓起!记录下AcWing刷过的题目,记录每一个瞬间。附上汇总贴:AcWing算法基础课打卡|汇总788逆序对的数量【题目描述】给定一个长度为nnn的整数数列,请你......
  • 让 AI 更懂你:微调、RLHF、强化学习微调和偏好微调,大模型训练的“进阶秘籍”
    以ChatGPT为代表的大语言模型(LLM)展现出了惊人的能力,能写诗、作画、编代码,甚至和你聊天谈心。但你知道这些聪明的AI模型是如何炼成的吗?除了海量数据的“喂养”之外,还需要一些特殊的训练技巧,才能让它们更好地理解和执行我们的指令。(关注公众号“AI演进”,获取更多AI知识)1.微......
  • SQL进阶实战技巧:即时订单比例问题
    目录0需求描述1数据准备2问题分析3小结往期精彩0需求描述订单配送中,如果期望配送日期和下单日期相同,称为即时订单,如果期望配送日期和下单日期不同,称为计划订单。请从配送信息表(delivery_info)中求出每个用户的首单(用户的第一个订单)中即时订单的比例,保留两位......