• [CSP-S模拟测试]:中间值(二分)


    题目背景

    $Maxtir$喜欢序列的中间值。


    题目传送门(内部题127)


    输入格式

      第一行输入两个正整数$n,m$,其中$m$是操作和询问次数。
      接下来两行每行输入$n$个非负整数,每一行分别表示两个序列$a,b$的初始值。
      接下来$m$行,每行输入一个操作或询问,以“$1 x y z$或$2 l_1 r_1 l_2 r_2$”的形式给出。
      对于$1$操作,保证$xin [0,1]$,若$x=0$,将$a_y$修改成$z$,否则将$b_y$修改成$z$,保证修改前后序列$a,b$都是非严格单调递增的。
      对于$2$操作,输出$a$序列的$[l_1,r_1]$区间与的$b$序列的$[l_2,r_2]$区间合并后形成的新区间的中间值,数据保证两个区间长度之和为奇数。


    输出格式

      对于每个询问,输出一行一个整数$ans$表示答案。


    样例

    样例输入:

    5 5
    12 41 46 68 69  
    35 61 82 84 96  
    2 1 4 3 5
    1 0 5 75
    2 2 4 3 4
    2 3 4 1 5
    2 1 4 2 4

    样例输出:

    68
    68
    68
    61


    数据范围与提示

      对于$30\%$的数据,满足$nleqslant 3,000,mleqslant 2,000$
      对于$70\%$的数据,满足$nleqslant 10^5,mleqslant 2 imes 10^5$
      对于$100\%$的数据,满足$nleqslant 5 imes 10^5,mleqslant 10^6$
      $0leqslant a_i,b_i,zleqslant 10^9,1leqslant l_1leqslant r_1leqslant n,1leqslant l_2leqslant r2leqslant n$
      由于本题输入数据量较大,使用 scanf 读入数据也需要花费较多时间,建议采用下面的代码来读入一个非负整数。

    int ri() {
    	char c = getchar(); int x = 0; for(;c < '0' || c > '9'; c = getchar());
    	for(;c >= '0' && c <= '9'; c = getchar()) x = x * 10 - '0' + c; return x;
    }
    

    题解

    考虑如何利用单调不降的性质。

    可以二分答案。

    考虑如何$judge$,现在$a$上二分,再在$b$上二分(设当前二分的位置的左侧都位于中位数的左侧,反之同理),时间复杂度$Theta(nlog^2 n)$;那么恭喜你被卡常了。

    考虑怎么优化,如果我们在$a$上二分出来一个位置,那么由于已经知道了总长度,所以还能知道对应的$b$上的位置,于是就剪掉了一个$log$。

    需要注意的是边界问题,有很多处理方法,耐心调就好了。

    温馨提醒:此题卡常,建议使用$AE86$

    时间复杂度:$Theta(nlog n)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int fh[2][500001];
    namespace ae86{
        const int bufl=1<<15;
        char buf[bufl],*s=buf,*t=buf;
        inline int fetch(){
            if(s==t){t=(s=buf)+fread(buf,1,bufl,stdin);if(s==t)return EOF;}
            return*s++;
        }
        inline int read(){
            int a=0,b=1,c=fetch();
            while(!isdigit(c))b^=c=='-',c=fetch();
            while(isdigit(c))a=a*10+c-48,c=fetch();
            return b?a:-a;
        }
    }
    using ae86::read;
    void work1(){fh[read()][read()]=read();}
    void work2()
    {
    	int l1=read(),r1=read(),l2=read(),r2=read();
    	int len=(r1-l1+r2-l2+2)>>1;
    	int lft=l1,rht=r1;
    	while(lft<=rht)
    	{
    		int mid=(lft+rht)>>1;
    		int res=len-(mid-l1+1)+l2;
    		if(res==l2-1&&mid-l1&&fh[0][mid]<=fh[1][l2]){printf("%d
    ",fh[0][mid]);return;}
    		if(res<l2){rht=mid-1;continue;}
    		else if(res>r2){lft=mid+1;continue;}
    		if(fh[0][mid]>=fh[1][res]&&(fh[0][mid]<=fh[1][res+1]||res==r2)){printf("%d
    ",fh[0][mid]);return;}
    		if(fh[0][mid]>=fh[1][res])rht=mid-1;else lft=mid+1;
    	}
    	lft=l2,rht=r2;
    	while(lft<=rht)
    	{
    		int mid=(lft+rht)>>1;
    		int res=len-(mid-l2+1)+l1;
    		if(res==l1-1&&mid-l2&&fh[1][mid]<=fh[0][l1]){printf("%d
    ",fh[1][mid]);return;}
    		if(res<l1){rht=mid-1;continue;}
    		else if(res>r1){lft=mid+1;continue;}
    		if(fh[1][mid]>=fh[0][res]&&(fh[1][mid]<=fh[0][res+1]||res==r1)){printf("%d
    ",fh[1][mid]);return;}
    		if(fh[1][mid]>=fh[0][res])rht=mid-1;else lft=mid+1;
    	}
    }
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)fh[0][i]=read();
    	for(int i=1;i<=n;i++)fh[1][i]=read();
    	for(int i=1;i<=m;i++)(read()==1)?work1():work2();
    	return 0;
    }
    

    rp++

  • 相关阅读:
    "Illegal group reference"异常的分析
    一个基于WEB的js时间控件的实现
    ASP.NET网站的网络安全性
    关于"parseInt"
    【C#算法】冒泡排序 选择排序 插入排序 希尔排序转
    【c#】web.config续
    【C#】GridView用法
    [C#]接口引
    【SQL】DBCC
    【C#】泛型
  • 原文地址:https://www.cnblogs.com/wzc521/p/11814982.html
Copyright © 2020-2023  润新知