【Luogu】 P8500 [NOI2022] 冒泡排序

题目链接

点击打开链接

题目解法

一个一个性质考虑,然后得出正解
首先考虑把冒泡排序的交换次数转化为逆序对数

性质B

结论1: 没有限制的序列填的数一定单调不降
证明:考虑 a i > a j ( i < j ) a_i>a_j(i<j) ai>aj(i<j) 时交换 i , j i,j i,j,可以让 i , j i,j i,j 之间大于 a j a_j aj 小于 a i a_i ai 的数产生的逆序对贡献消失,而其他逆序对数的不变的,所以不会变劣

考虑对于一个没有限制的位置 i i i 的最优值(这里只是单独考虑它)
可以抽象一下问题,把限制按 V V V 从小到大排序,把下标小于 i i i 的数看做 A A A,下标大于 i i i 的数看做 B B B
那么根据结论1, i i i 只会和有限制的数产生贡献,其贡献 ( V < a i V<a_i V<ai B B B 的个数) + + + v > a i v>a_i v>ai A A A 的个数),其中的最小值便是单独考虑 i i i 位置的最优值

结论2: 单独考虑位置的最优值一定是单调不降的
因为随着 i i i 增大, A A A 会变多, B B B 会变少,不难发现 a i a_i ai 一定会上升,使 V < a i V<a_i V<ai B B B 的个数 和 v > a i v>a_i v>ai A A A 的个数 达到一种平衡

然后就可以用线段树维护了,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

性质C

不难发现 a L = V a_L=V aL=V 时是最优的,否则可以交换
现在限制变成了有一些位置固定,一些位置只能 ≥ V i \ge V_i Vi
考虑贪心:从大到小枚举每个位置,先只考虑一些位置 ≥ V i \ge V_i Vi 的限制(包括固定的位置),然后得出当前位置的精确最小值,然后再用精确最小值去更新前面的位置
证明不会
用线段树维护,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

正解

考虑将 V V V 从大到小排序,这样可以使做到 i i i 时,前面的限制不用变
考虑对于相同的 V V V,将 l l l 从大到小排序,然后尽量选最开头的,如果一个区间已经有位置被选过了就跳过,然后把这个区间都标记 ≥ V \ge V V,使 V ′ < V V'<V V<V 的区间不能选 V ′ ′ = V V''=V V′′=V 的区间的位置
显然,这样可以使相同的 V V V 限制最少的位置
不合法的情况是一个区间无法选 = V =V =V 的最小位置,即前面 V ′ > V V'>V V>V 的区间已经把整个 V ′ ′ = V V''=V V′′=V 的区间全部标记过了
然后就变成了性质 C C C 的问题
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

代码里面性质 B B B 和 性质 C C C 单独的部分都有

#include <bits/stdc++.h>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N=1000100;
struct Seg{int l,r,v;
}limit[N];
int n,m;
inline int read(){int FF=0,RR=1;char ch=getchar();for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;return FF*RR;
}
namespace solveB{int disc[N];bool cmp(const Seg &x,const Seg &y){ return x.l<y.l;}struct SegmentTree{int seg[N<<2],tag[N<<2];void clear(int len){ for(int i=1;i<=len;i++) seg[i]=tag[i]=0;}void pushdown(int x){seg[x<<1]+=tag[x],tag[x<<1]+=tag[x];seg[x<<1^1]+=tag[x],tag[x<<1^1]+=tag[x];tag[x]=0;}void modify(int l,int r,int x,int L,int R,int val){if(L<=l&&r<=R){ seg[x]+=val,tag[x]+=val;return;}pushdown(x);int mid=(l+r)>>1;if(mid>=L) modify(l,mid,x<<1,L,R,val);if(mid<R) modify(mid+1,r,x<<1^1,L,R,val);seg[x]=min(seg[x<<1],seg[x<<1^1]); }}sg;struct BinaryTree{int tr[N];void add(int x,int val,int lim){ for(;x<=lim;x+=lowbit(x)) tr[x]+=val;}int ask(int x){int res=0;for(;x;x-=lowbit(x)) res+=tr[x];return res;}}tr;void solve(){for(int i=1;i<=m;i++) disc[i]=limit[i].v;sort(disc+1,disc+m+1);int cnt=unique(disc+1,disc+m+1)-disc-1;for(int i=1;i<=m;i++) limit[i].v=lower_bound(disc+1,disc+cnt+1,limit[i].v)-disc;sort(limit+1,limit+m+1,cmp);int j=1;for(int i=2;i<=m;i++){if(limit[i].l!=limit[i-1].l) limit[++j]=limit[i];else if(limit[i].v!=limit[i-1].v){ puts("-1");return;}}m=j;LL ans=0;sg.clear(cnt<<2);for(int i=1;i<=m;i++) if(limit[i].v<cnt) sg.modify(1,cnt,1,limit[i].v+1,cnt,1);for(int i=1;i<m;i++){if(limit[i].v<cnt) sg.modify(1,cnt,1,limit[i].v+1,cnt,-1);if(limit[i].v>1) sg.modify(1,cnt,1,1,limit[i].v-1,1);ans+=1ll*sg.seg[1]*(limit[i+1].l-limit[i].l-1);// cout<<"+++"<<sg.seg[1]<<' '<<limit[i+1].l<<' '<<limit[i].l<<' '<<ans<<'\n';}// cout<<ans<<'\n';for(int i=m;i;i--){if(limit[i].v>1) ans+=tr.ask(limit[i].v-1);tr.add(limit[i].v,1,cnt);}for(int i=1;i<=m;i++) tr.add(limit[i].v,-1,cnt);printf("%lld\n",ans);}bool check(){for(int i=1;i<=m;i++) if(limit[i].l!=limit[i].r) return false;return true;}
}
namespace solveC{int disc[N],low[N],val[N];struct SegmentTree{int seg[N<<2],tag[N<<2],pos[N<<2];void build(int l,int r,int x){seg[x]=0,tag[x]=0,pos[x]=l;if(l==r) return;int mid=(l+r)>>1;build(l,mid,x<<1),build(mid+1,r,x<<1^1);}void pushdown(int x){seg[x<<1]+=tag[x],tag[x<<1]+=tag[x];seg[x<<1^1]+=tag[x],tag[x<<1^1]+=tag[x];tag[x]=0;}void modify(int l,int r,int x,int L,int R,int val){if(L<=l&&r<=R){ seg[x]+=val,tag[x]+=val;return;}pushdown(x);int mid=(l+r)>>1;if(mid>=L) modify(l,mid,x<<1,L,R,val);if(mid<R) modify(mid+1,r,x<<1^1,L,R,val);if(seg[x<<1]<=seg[x<<1^1]) pos[x]=pos[x<<1];else pos[x]=pos[x<<1^1];seg[x]=min(seg[x<<1],seg[x<<1^1]); }pii query(int l,int r,int x,int L,int R){if(L<=l&&r<=R) return make_pair(seg[x],pos[x]);pushdown(x);int mid=(l+r)>>1;if(mid>=L&&mid<R){pii tl=query(l,mid,x<<1,L,R),tr=query(mid+1,r,x<<1^1,L,R);if(tl.first<tr.first) return tl;else return tr;}if(mid>=L) return query(l,mid,x<<1,L,R);return query(mid+1,r,x<<1^1,L,R);}}sg;struct BinaryTree{int tr[N];void add(int x,int val,int lim){ for(;x<=lim;x+=lowbit(x)) tr[x]+=val;}int ask(int x){int res=0;for(;x;x-=lowbit(x)) res+=tr[x];return res;}}tr;void solve(){for(int i=1;i<=m;i++) disc[i]=limit[i].v;sort(disc+1,disc+m+1);for(int i=1;i<=m;i++) limit[i].v=lower_bound(disc+1,disc+m+1,limit[i].v)-disc;for(int i=1;i<=n;i++) low[i]=val[i]=-1;for(int i=1;i<=m;i++){val[limit[i].l]=limit[i].v;for(int j=limit[i].l;j<=limit[i].r;j++) low[j]=limit[i].v;}sg.build(1,m,1);for(int i=1;i<=n;i++) if(low[i]>1) sg.modify(1,m,1,1,low[i]-1,1);for(int i=n;i;i--){if(low[i]>1) sg.modify(1,m,1,1,low[i]-1,-1);if(val[i]==-1) val[i]=sg.query(1,m,1,low[i],m).second;if(val[i]+1<=m) sg.modify(1,m,1,val[i]+1,m,1);}LL ans=0;for(int i=n;i;i--){if(val[i]>1) ans+=tr.ask(val[i]-1);tr.add(val[i],1,m);}for(int i=1;i<=n;i++) tr.add(val[i],-1,m);printf("%lld\n",ans);}
}
namespace SOLVE{int fa[N],disc[N],val[N],low[N];vector<pii> T[N];int get_father(int x){ return x==fa[x]?x:fa[x]=get_father(fa[x]);}struct SegmentTree{int seg[N<<2],tag[N<<2],pos[N<<2];void build(int l,int r,int x){seg[x]=0,tag[x]=0,pos[x]=l;if(l==r) return;int mid=(l+r)>>1;build(l,mid,x<<1),build(mid+1,r,x<<1^1);}void pushdown(int x){seg[x<<1]+=tag[x],tag[x<<1]+=tag[x];seg[x<<1^1]+=tag[x],tag[x<<1^1]+=tag[x];tag[x]=0;}void modify(int l,int r,int x,int L,int R,int val){if(L<=l&&r<=R){ seg[x]+=val,tag[x]+=val;return;}pushdown(x);int mid=(l+r)>>1;if(mid>=L) modify(l,mid,x<<1,L,R,val);if(mid<R) modify(mid+1,r,x<<1^1,L,R,val);if(seg[x<<1]<=seg[x<<1^1]) pos[x]=pos[x<<1];else pos[x]=pos[x<<1^1];seg[x]=min(seg[x<<1],seg[x<<1^1]); }pii query(int l,int r,int x,int L,int R){if(L<=l&&r<=R) return make_pair(seg[x],pos[x]);pushdown(x);int mid=(l+r)>>1;if(mid>=L&&mid<R){pii tl=query(l,mid,x<<1,L,R),tr=query(mid+1,r,x<<1^1,L,R);if(tl.first<tr.first) return tl;else return tr;}if(mid>=L) return query(l,mid,x<<1,L,R);return query(mid+1,r,x<<1^1,L,R);}}sg;struct BinaryTree{int tr[N];void add(int x,int val,int lim){ for(;x<=lim;x+=lowbit(x)) tr[x]+=val;}int ask(int x){int res=0;for(;x;x-=lowbit(x)) res+=tr[x];return res;}}tr;void solve(){for(int i=1;i<=n+1;i++) fa[i]=i,low[i]=val[i]=-1;for(int i=1;i<=m;i++) disc[i]=limit[i].v;sort(disc+1,disc+m+1);for(int i=1;i<=m;i++) limit[i].v=lower_bound(disc+1,disc+m+1,limit[i].v)-disc;for(int i=1;i<=m;i++) T[i].clear();for(int i=1;i<=m;i++) T[limit[i].v].push_back(make_pair(limit[i].l,limit[i].r));bool haveans=1;for(int i=m;i;i--){sort(T[i].begin(),T[i].end(),greater<pii>());int mxl=n+5;for(pii t:T[i])if(t.second<mxl){int np=get_father(t.first);if(np>t.second){ haveans=0;break;}mxl=np,val[np]=i;}// cerr<<"+++";for(pii t:T[i]) for(int j=get_father(t.first);j<=t.second;j=get_father(j)) low[j]=i,fa[j]=j+1;// cerr<<"---";}if(!haveans){ puts("-1");return;}// for(int i=1;i<=n;i++) cout<<val[i]<<' ';cout<<'\n';sg.build(1,m,1);for(int i=1;i<=n;i++) if(low[i]>1) sg.modify(1,m,1,1,low[i]-1,1);for(int i=n;i;i--){if(low[i]>1) sg.modify(1,m,1,1,low[i]-1,-1);if(val[i]==-1) val[i]=sg.query(1,m,1,low[i],m).second;if(val[i]+1<=m) sg.modify(1,m,1,val[i]+1,m,1);}LL ans=0;for(int i=n;i;i--){if(val[i]>1) ans+=tr.ask(val[i]-1);tr.add(val[i],1,m);}for(int i=1;i<=n;i++) tr.add(val[i],-1,m);printf("%lld\n",ans);}
}
int main(){// freopen("bubble6.in","r",stdin);// freopen("bubble.out","w",stdout);int T=read();while(T--){n=read(),m=read();for(int i=1;i<=m;i++) limit[i].l=read(),limit[i].r=read(),limit[i].v=read();SOLVE::solve();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/66816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【vue】vue前端实现随机验证码(数字、字母混合)功能

效果图&#xff1a;使用canvas组件对随机的数字字母添加插画背景、干扰线、干扰点 1、在components文件夹下新建securityCode.vue文件&#xff0c;代码&#xff1a; <template><canvas id"s-canvas" :width"contentWidth" :height"contentH…

用Visual Studio 2022的.map文件来查看C++变量在内存中的布局情况

先看几个实例 代码1 #include <iostream> int data_arr[32768]; int main() {data_arr[1] 11;std::cout<<"data_arr[1]: " << data_arr[1] << std::endl;return data_arr[1]; } 上述代码在Win10 X64&#xff0c;MSVC Release模式下编译&…

C#安装“Windows 窗体应用(.NET Framework)”

目录 背景: 第一步: 第二步: 第三步&#xff1a; 总结: 背景: 如下图所示:在Visual Studio Installer创建新项目的时候&#xff0c;想要添加windows窗体应用程序&#xff0c;发现里面并没有找到Windows窗体应用(.NET Framework)模板&#xff0c;快捷搜索也没有发现&#…

22.3D等距社交媒体菜单的悬停特效

效果 源码 <!doctype html> <html><head><meta charset="utf-8"><title>CSS Isometric Social Media Menu</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.…

Apache arrow顶级项目调试

Apache arrow顶级项目调试 arrow官方从7.x版本开始提供了一个gdb工具&#xff0c;叫做gdb_arrow.py&#xff0c;可以在仓库里面下载下来。 调试原理可以阅读之前写的文章&#xff1a; 玩转C调试之Python的GDB库增强 使用办法非常简单&#xff0c;直接&#xff1a; source /code…

Kubernetes技术--k8s核心技术集群的安全机制RBAC

1.引入 我们在访问k8s的集群的时候,需要经过一下几个步骤: -a:认证 -1).传输安全:对外是不暴露端口:8080,只能够在内部访问,对外使用的是6443端口。 -2).客户端认证的常用几种方式: -https证书 基于ca证书 -https token认证 通过token识别用户 -https <

springboot web开发登录拦截器

在SpringBoot中我们可以使用HandlerInterceptorAdapter这个适配器来实现自己的拦截器。这样就可以拦截所有的请求并做相应的处理。 应用场景 日志记录&#xff0c;可以记录请求信息的日志&#xff0c;以便进行信息监控、信息统计等。权限检查&#xff1a;如登陆检测&#xff…

SQL sever中用户管理

目录 一、用户管理常见方法 二、用户管理方法示例 2.1. 创建登录账户&#xff1a; 2.1.1 检查是否创建账户成功&#xff1a; 2.2. 创建数据库用户&#xff1a; 2.2.1检查用户是否创建成功&#xff1a; 2.3. 授予权限&#xff1a; 2.3.1授予 SELECT、INSERT 和 U…

原型模式:复制对象的技巧

欢迎来到设计模式系列的第六篇文章&#xff01;在前面的几篇文章中&#xff0c;我们已经学习了一些常见的设计模式&#xff0c;今天我们将继续探讨另一个重要的设计模式——原型模式。 原型模式简介 原型模式是一种创建型设计模式&#xff0c;它主要用于复制对象。原型模式通…

【教程】PyTorch Timer计时器

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] OpenCV的Timer计时器可以看这篇&#xff1a;Python Timer和TimerFPS计时工具类 Timer作用说明&#xff1a;统计某一段代码的运行耗时。 直接上代码&#xff0c;开箱即用。 import time import torch import os …

springboot设置日志输出级别

一、日志等级 trace&#xff1a;最低等级 debug&#xff1a;调试用&#xff0c;通常用于跟踪程序进展 info: 记录用&#xff0c;通常用于记录程序行为 warn&#xff1a;警告 error&#xff1a;错误 fatal&#xff1a;灾难性错误&#xff0c;最高等级 配置application.yml 实现…

L1-056 猜数字(Python实现) 测试点全过

前言&#xff1a; {\color{Blue}前言&#xff1a;} 前言&#xff1a; 本系列题使用的是&#xff0c;“PTA中的团体程序设计天梯赛——练习集”的题库&#xff0c;难度有L1、L2、L3三个等级&#xff0c;分别对应团体程序设计天梯赛的三个难度。更新取决于题目的难度&#xff0c;…

什么是BEM命名规范(Block-Element-Modifier Notation)?它有什么优势?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ BEM命名规范&#xff08;Block-Element-Modifier Notation&#xff09;⭐ BEM命名结构⭐ 优势⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎…

如何解决分库分表主键问题?

分析&回答 从问题角度出发&#xff1a;我们需要一个全局唯一的 id 来支持&#xff0c;排序问题等。这都是你实际生产环境中必须考虑的问题。可以先看下我们之前的文章分布式系统唯一ID如何生成&#xff1f; 雪花算法和雪花算法的变种是大家常用的 喵呜面试助手&#xff1…

春秋云镜 CVE-2018-1273

春秋云镜 CVE-2018-1273 Spring-data-commons 远程命令执行漏洞 靶标介绍 Spring Data是一个用于简化数据库访问&#xff0c;并支持云服务的开源框架&#xff0c;Spring Data Commons是Spring Data下所有子项目共享的基础框架。Spring Data Commons 在2.0.5及以前版本中&…

【算法】滑动窗口

滑动窗口应用场景 关键词&#xff1a; 满足xxx条件&#xff08;计算结果&#xff0c;出现次数&#xff0c;同时包含&#xff09; 最长/最短 子串/子数组/子序列 例如&#xff1a;长度最小的子数组 滑动窗使用思路&#xff08;寻找最长&#xff09; 核心&#xff1a;左右双指…

git大文件推送报错

报错信息 不多掰扯&#xff0c;直接上报错信息和截图 Delta compression using up to 8 threadsRPC failde; HTTP 413 curl 22 The requested URL returned error: 413 Request Entity Too Large从以上的报错信息不难看出推送仓库的时候&#xff0c;请求体过大&#xff0c;为…

第五讲Java面向对象——类及类的成员

前言 前面几讲,我们讲解了java的基础知识,也写了很多代码,有没有发现,每次编写代码前都会新建一个类,并且开头是public class修饰。可能有些同学不知道什么是类,以及前面我们提到方法。那么本讲,就要开始深入了解他们。 在开始讲解,我们将先了解一下编程的思想,面向对…

八、SpringBoot集成Kafka

目录 一、添加依赖二、SpringBoot 生产者三、SpringBoot 消费者 一、添加依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><depend…

8.Redis-set

Set 常用命令saddsmemberssismemberscardspopsmovesrem集合间操作sinter 交集sinterstoresunion 并集sunionstoresdiff 差集sdiffstore 命令总结 内部编码应用场景使用 set来保存用户的“标签” set(集合)就是把一些有关联的数据放刀一起。 它与list的区别如下&#xff1a; 集合…