首页 > 其他分享 >题解 [HEOI2016/TJOI2016] 排序

题解 [HEOI2016/TJOI2016] 排序

时间:2023-09-28 12:13:29浏览次数:41  
标签:&& int 题解 nd mid while TJOI2016 HEOI2016 pushdown

题目链接

看到这道题按照套路首先想到二分答案(即二分 \(q\) 位置上的数,记作 \(mid\))。

再按照套路将大于 \(mid\) 的数字设为 \(1\),将等于 \(mid\) 的数设为 \(2\),小于 \(mid\) 的数字设为 \(0\)。

那么对于区间 \([l,r,0]\) 操作,应该先讲 \(0,1,2\) 的数量找出来,然后按照从小到大的顺序 \(0,2,1\) 进行区间赋值,并支持区间求和,这用线段树维护即可。而 \(opt=1\) 的情况也是同理。

现在考虑二分指针如何移动。首先,\(mid,pos\) 两者并不满足单调性,也就是说,\(mid\) 增大,位置不一定取得到后面,减小同理。这时便要从另一个角度思考问题。

如果 \(a_q\) 是 \(1\),说明答案比当前数字大,我们将指针右移;\(a_q=2\),说明答案正好是 \(mid\);\(a_q=0\),说明答案比当前数字小,将指针左移。

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

typedef long long LL;
inline int read() {
    int sum=0,flag=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') flag=-1; c=getchar();}
    while(c>='0'&&c<='9') {sum=sum*10+c-'0'; c=getchar();}
    return sum*flag;
}

const int N=1e5+10;
int n,m,q;
int a[N];
int ql[N],qr[N],qt[N];
int tr[N<<2][3],tag[N<<2][3];
struct node {
    int a0,a1,a2;
    friend node operator + (node x,node y) {
        return {x.a0+y.a0,x.a1+y.a1,x.a2+y.a2};
    }
};

inline void pushup(int nd) {
    for(int i=0;i<=2;i++) tr[nd][i]=tr[nd<<1][i]+tr[nd<<1|1][i];
}

inline void add(int nd,int l,int r,int a0,int a1,int a2) {
    tr[nd][0]=tr[nd][1]=tr[nd][2]=0;
    tag[nd][0]=tag[nd][1]=tag[nd][2]=0;
    if(a0) {tr[nd][0]=r-l+1; tag[nd][0]=1;}
    if(a1) {tr[nd][1]=r-l+1; tag[nd][1]=1;}
    if(a2) {tr[nd][2]=r-l+1; tag[nd][2]=1;}
}

inline void pushdown(int nd,int l,int r) {
    if(!tag[nd][0]&&!tag[nd][1]&&!tag[nd][2]) return ;
    int mid=l+r>>1;
    add(nd<<1,l,mid,tag[nd][0],tag[nd][1],tag[nd][2]);
    add(nd<<1|1,mid+1,r,tag[nd][0],tag[nd][1],tag[nd][2]);
    tag[nd][0]=tag[nd][1]=tag[nd][2]=0;
}

void change(int nd,int l,int r,int x,int y,int a0,int a1,int a2) {
    if(l>y||r<x) return ;
    if(x>y) return ;
    if(l>=x&&r<=y) return add(nd,l,r,a0,a1,a2);
    int mid=l+r>>1;
    pushdown(nd,l,r);
    change(nd<<1,l,mid,x,y,a0,a1,a2);
    change(nd<<1|1,mid+1,r,x,y,a0,a1,a2);
    pushup(nd);
}

node query(int nd,int l,int r,int x,int y) {
    if(l>y||r<x) return {0,0,0};
    if(l>=x&&r<=y) return {tr[nd][0],tr[nd][1],tr[nd][2]};
    int mid=l+r>>1;
    pushdown(nd,l,r);
    return query(nd<<1,l,mid,x,y)+query(nd<<1|1,mid+1,r,x,y);
}

int ask(int nd,int l,int r,int p) {
    if(l==r) {
        if(tr[nd][0]) return 0;
        if(tr[nd][1]) return 1;
        if(tr[nd][2]) return 2;
    }
    int mid=l+r>>1;
    pushdown(nd,l,r);
    if(l<=p&&p<=mid) return ask(nd<<1,l,mid,p);
    else return ask(nd<<1|1,mid+1,r,p);
}

int check(int x) {
    memset(tr,0,sizeof(tr));
    memset(tag,0,sizeof(tag));
    for(int i=1;i<=n;i++) {
        if(a[i]<x) change(1,1,n,i,i,1,0,0);
        if(a[i]==x) change(1,1,n,i,i,0,0,1);
        if(a[i]>x) change(1,1,n,i,i,0,1,0);
    }
    for(int i=1;i<=m;i++) {
        node num=query(1,1,n,ql[i],qr[i]);
        if(qt[i]==0) {
            change(1,1,n,ql[i],ql[i]+num.a0-1,1,0,0);
            change(1,1,n,ql[i]+num.a0,ql[i]+num.a0+num.a2-1,0,0,1);
            change(1,1,n,ql[i]+num.a0+num.a2,qr[i],0,1,0);
        }
        else {
            change(1,1,n,ql[i],ql[i]+num.a1-1,0,1,0);
            change(1,1,n,ql[i]+num.a1,ql[i]+num.a1+num.a2-1,0,0,1);
            change(1,1,n,ql[i]+num.a1+num.a2,qr[i],1,0,0);
        }
    }
    return ask(1,1,n,q);
}

int main() {
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);

    cin>>n>>m;
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=m;i++) {
        qt[i]=read();
        ql[i]=read();
        qr[i]=read();
    }
    cin>>q;
    int l=1,r=n;
    while(l<=r) {
        int mid=l+r>>1;
        int k=check(mid);
        if(k==1) l=mid+1;
        if(k==2) {cout<<mid; return 0;}
        if(k==0) r=mid-1;
    }

    return 0;
}

标签:&&,int,题解,nd,mid,while,TJOI2016,HEOI2016,pushdown
From: https://www.cnblogs.com/zhangyuzhe/p/17735462.html

相关文章

  • 题解 CF1873H【Mad City】
    其他题解怎么又Tarjan又Dijkstra的,这是div4H的样子吗,来个简单好写的做法。题面里的人名太复杂了,本题解中称为警察和小偷。注意到,如果小偷成功到达了环上,那么一定不会被警察抓到。因为小偷知道警察下一步会走到哪里,他可以执行相同的操作(顺时针/逆时针/静止),使得他和警察之间......
  • [ARC124C] LCM of GCDs 题解
    题面给定\(N\)个正整数对\((a_i,b_i)\)和两个初始为空的集合\(S,T\),你可以选择将每个数对的两个元素划分到两个不同的集合中。求\[\max\operatorname{lcm}(\gcd\limits_{x\inS}x,\gcd\limits_{y\inT}y)\](\(1\leN\le50,1\lea_i,b_i\le10^9\))。题解首先,......
  • P4370 [Code+#4] 组合数问题2-题解-有关对数的小技巧
    20230927P4370[Code+#4]组合数问题2-solStatement传送门给你两个数\(n,k\),要求对于组合数\(C_{a}^{b}\)找到任何\(k\)个,让他们的和最大,且组合数各不相同,当且仅当\(a,b\)不完全相同时,组合数不同。Solution首先,很容易发现\(C_{n}^{m}\gtc_{n-1}^{m}\),所......
  • CF364D Ghd 题解
    CF364DGhd题解题目大意给定一个长度为\(n\)的序列,你需要从中选出一个元素个数不少于\(\left\lceil{\frac{n}{2}}\right\rceil\)的子序列,使得这个子序列中所有元素的\(\gcd\)最大。分析数据范围吓人。\(10^6\),但是根本想不到什么\(O(n\logn)\)或\(O(n)\)的算法......
  • [ARC125B] Squares 题解
    题意给定正整数\(N\),求满足如下条件的正整数对\((x,y)\)的数量:\(1\lex,y\leN\)\(x^2-y\)为完全平方数(\(0\)也是完全平方数)(\(1\leN\le10^{12}\))。题解因为\(x^2-y\)为完全平方数,设其为\(z^2\),那么有\[\begin{aligned}x^2-y=z^2\\\end{al......
  • [题解] Codeforces Round 900(Div.3) E~F
    CodeforcesRound900(Div.3)E~FE.Iva&Pav因为按位与的结果不会随着越多数字的增加而增加,因此我们可以利用这个性质二分出右端点,只需要一个可以查询区间的数据结构即可。或者是按位考虑第\(i\)个数字的第\(k\)位,后缀最近的\(0\)的位置,按位考虑也可以。但是这题使用二分......
  • ACAM 学习笔记 | 附 YbtOJ 全部题解
    怎么有人现在才学ACAM呢。好像比SAM简单挺多啊,也不记得当时是哪里看不懂。AC自动机(✔)自动AC机(✘)概述ACAM(Aho–CorasickAutomaton),是用来解决多模式串匹配的字符串算法。它的结构是个DAG,其中点表示状态,边表示转移。这一点上各种自动机都是相同的。具体来说,可以感性......
  • [题解]CF1878E Iva & Pav
    CF是没题考了吧,每场都出二进制拆位。思路首先我们可以二分\(r\),因为\(r\)越大,按位与一定只会小于等于\(r\)小的情况。那么,我们可以用\(num_{i,j}\)记录\(a_j\)第\(i\)位的二进制情况。如果我们对\(num_{i,j}\)做一个前缀和,如果\(num_{i,r}-num_{i,l-1}=r......
  • 安装 SonarQube后sonarqube-sonarqube无法启动的问题解决
    1.前言我的环境:k8s集群(version1.23.6),安装了Kubesphere(versionv3.4)作为可视化界面,最近想要推动团队走CICD,于是在Kubesphere中启用了devops组件,参考:https://kubesphere.io/zh/docs/v3.4/pluggable-components/devops/。组件安装完成后,需要将Sonarqube集成到流水线中,于是又安装......
  • luogu P4819 [中山市选] 杀人游戏 题解 【强连通分量+缩点】
    目录题目链接思路分析代码题目链接P4819思路分析首先考虑这道题的连通性。容易发现这种类型的题目会容易产生环形的状态转移。假设我们知道了其中的一个点是否是黑白点,那么我们就可以知道所有点是否是黑白点。容易陷入一个误区:我们只能通过一个点知道他所相邻的最直接的点,如何......