• [洛谷P3939]:数颜色(二分)


    题目传送门


    题目描述

    小$C$的兔子不是雪白的,而是五彩缤纷的。每只兔子都有一种颜色,不同的兔子可能有相同的颜色。小$C$把她标号从$1$到$n$的$n$只兔子排成长长的一排,来给他们喂胡萝卜吃。排列完成后,第$i$只兔子的颜色是$a_i$。
    俗话说得好,“萝卜青菜,各有所爱”。小$C$发现,不同颜色的兔子可能有对胡萝卜的不同偏好。比如,银色的兔子最喜欢吃金色的胡萝卜,金色的兔子更喜欢吃胡萝卜叶子,而绿色的兔子却喜欢吃酸一点的胡萝卜……为了满足兔子们的要求,小$C$十分苦恼。所以,为了使得胡萝卜喂得更加准确,小$C$想知道在区间$[l_j,r_j]$里有多少只颜色为$c_j$的兔子。不过,因为小$C$的兔子们都十分地活跃,它们不是很愿意待在一个固定的位置;与此同时,小$C$也在根据她知道的信息来给兔子们调整位置。所以,有时编号为$x_j$和$x_{j+1}$的两只兔子会交换位置。
    小$C$被这一系列麻烦事给难住了。你能帮帮她吗?


    输入格式

    输入第$1$行两个正整数$n,m$。
    输入第$2$行$n$个正整数,第$i$个数表示第$a_i$只兔子的颜色 。
    输入接下来$m$行,每行为以下两种中的一种:
    “$1 l_j r_j c_j$”:询问在区间$[l_j,r_j]$里有多少只颜色为$c_j$的兔子;
    “$2 x_j$:$x_j$和$x_{j+1}$两只兔子交换了位置。


    输出格式

    对于每个$1$操作,输出一行一个正整数,表示你对于这个询问的答案。


    样例

    样例输入1:

    6 5
    1 2 3 2 3 3
    1 1 3 2
    1 4 6 3
    2 3
    1 1 3 2
    1 4 6 3

    样例输出1:

    1
    2
    2
    3

    样例输入2:

    10 9
    1 2 3 4 5 6 1 2 3 4
    1 1 3 3
    1 4 6 3
    2 3
    1 1 3 3
    1 4 6 3
    1 1 10 4
    1 1 10 3
    1 1 10 2
    1 1 10 1

    样例输出2:

    1
    0
    0
    1
    2
    2
    2
    2


    数据范围与提示

    样例$1$说明:

    前两个$1$操作和后两个$1$操作对应相同;在第三次的$2$操作后,$3$号兔子和$4$号兔子交换了位置,序列变为$1 2 2 3 3 3$。

    数据范围:

    子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解决一部分测试数据。
    对于所有测试点,有$1leqslant l_jleqslant r_jleqslant n,1leqslant x_jleqslant n$。
    每个测试点的数据规模及特点如下表:

    测试点       $n$                    操作$1$             操作$2$             $a_i,c_j$           特殊性质$1$           特殊性质$2$
        $1$           $2$                     $6$                     $0$                     $leqslant  2$                     $surd$                          $surd$
        $2$           $2$                     $1000$             $1000$              $leqslant 1000$              $surd$                          $surd$
        $3$          $1000$              $1000$              $0$                     $leqslant 1000$              $ imes$                          $ imes$
        $4$          $1000$              $1000$              $1000$              $leqslant  10$                   $ imes$                          $ imes$
        $5$          $1000$              $1000$              $1000$              $leqslant 1000$              $ imes$                         $surd$
        $6$          $1000$              $1000$              $1000$              $leqslant 1000$              $ imes$                         $ imes$
        $7$          $5 imes {10}^4$        $5 imes {10}^4$        $0$                     $leqslant 5 imes {10}^4$        $surd$                         $ imes$
        $8$          $5 imes {10}^4$        $5 imes {10}^4$        $5 imes {10}^4$       $leqslant 10$                   $ imes$                         $ imes$
        $9$          $5 imes {10}^4$        $5 imes {10}^4$        $5 imes {10}^4$       $leqslant 5 imes {10}^4$        $ imes$                         $surd$
        $10$        $5 imes {10}^4$        $5 imes {10}^4$        $5 imes {10}^4$       $leqslant 5 imes {10}^4$        $ imes$                         $ imes$
        $11$        $5 imes {10}^4$        $5 imes {10}^4$        $5 imes {10}^4$       $leqslant 5 imes {10}^4$        $ imes$                         $ imes$
        $12$        $5 imes {10}^4$        $5 imes {10}^4$        $5 imes {10}^4$       $leqslant 5 imes {10}^4$        $ imes$                         $ imes$
        $13$        $5 imes {10}^4$        $5 imes {10}^4$        $5 imes {10}^4$       $leqslant 5 imes {10}^4$        $ imes$                         $ imes$
        $14$        $3 imes {10}^5$        $3 imes {10}^5$        $3 imes {10}^5$       $leqslant 3 imes {10}^5$        $ imes$                         $ imes$
        $15$        $3 imes {10}^5$        $3 imes {10}^5$        $3 imes {10}^5$       $leqslant 10$                   $ imes$                         $ imes$
        $16$        $3 imes {10}^5$        $3 imes {10}^5$        $3 imes {10}^5$       $leqslant 3 imes {10}^5$        $ imes$                         $surd$
        $17$        $3 imes {10}^5$        $3 imes {10}^5$        $3 imes {10}^5$       $leqslant 3 imes {10}^5$        $surd$                         $ imes$
        $18$        $3 imes {10}^5$        $3 imes {10}^5$        $3 imes {10}^5$       $leqslant 3 imes {10}^5$        $ imes$                         $ imes$
        $19$        $3 imes {10}^5$        $3 imes {10}^5$        $3 imes {10}^5$       $leqslant 3 imes {10}^5$        $ imes$                         $ imes$
        $20$        $3 imes {10}^5$        $3 imes {10}^5$        $3 imes {10}^5$       $leqslant 3 imes {10}^5$        $ imes$                         $ imes$


    题解

    $30\%$算法:

    啥也甭管,暴力搞就好了。

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

    期望得分:$30$分(朴素),$60$分($luoguO2+$卡常)

    $65\%$算法:

    树套树。

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

    带修莫队。

    时间复杂度:$Theta(n^{frac{5}{3}})$。

    期望得分:$60 hicksim 100$分。

    $100\%$算法:

    记录每种颜色的每个兔子的出现位置,然后进行二分查找答案,操作$2$只需要改变坐标即可。

    需要注意的是,如果交换的两个兔子颜色一样不要交换它们,否则会导致坐标的无序。

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

    期望得分:$100$分。


    代码时刻

    $30\%$算法(朴素):

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int a[300001];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    	while(m--)
    	{
    		int opt;
    		scanf("%d",&opt);
    		if(opt==1)
    		{
    			int l,r,c,ans=0;
    			scanf("%d%d%d",&l,&r,&c);
    			for(int i=l;i<=r;i++)
    				if(a[i]==c)ans++;
    			printf("%d
    ",ans);
    		}
    		else
    		{
    			int x;
    			scanf("%d",&x);
    			swap(a[x],a[x+1]);
    		}
    	}
    	return 0;
    }
    

    $30\%$算法($luoguO2$+卡常):

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #pragma GCC optimize(s)
    using namespace std;
    int n,m;
    int a[300001];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
    	while(m--)
    	{
    		register int opt;
    		scanf("%d",&opt);
    		if(opt==1)
    		{
    			register int l,r,c,ans=0;
    			scanf("%d%d%d",&l,&r,&c);
    			for(register int i=l;i<=r;i++)
    				if(a[i]==c)ans++;
    			printf("%d
    ",ans);
    		}
    		else
    		{
    			register int x;
    			scanf("%d",&x);
    			swap(a[x],a[x+1]);
    		}
    	}
    	return 0;
    }
    

    $65\%$算法(常数小,可AC):

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int a[300001];
    int rt[300001],trsum[10000000],son[10000000][2],tot;
    void change(int &x,int l,int r,int to,int d)
    {
    	if(!x)x=++tot;
    	trsum[x]+=d;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(to<=mid)change(son[x][0],l,mid,to,d);
    	else change(son[x][1],mid+1,r,to,d);
    }
    int ask(int x,int l,int r,int L,int R)
    {
    	if(!x)return 0;
    	if(l==L&&r==R)return trsum[x];
    	int mid=(l+r)>>1;
    	if(L>mid)return ask(son[x][1],mid+1,r,L,R);
    	else if(R<=mid)return ask(son[x][0],l,mid,L,R);
    	else return ask(son[x][0],l,mid,L,mid)+ask(son[x][1],mid+1,r,mid+1,R);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		change(rt[a[i]],1,n,i,1);
    	}
    	while(m--)
    	{
    		int opt;
    		scanf("%d",&opt);
    		if(opt==1)
    		{
    			int l,r,c;
    			scanf("%d%d%d",&l,&r,&c);
    			printf("%d
    ",ask(rt[c],1,n,l,r));
    		}
    		else
    		{
    			int x;
    			scanf("%d",&x);
    			change(rt[a[x  ]],1,n,x  ,-1);
    			change(rt[a[x  ]],1,n,x+1, 1);
    			change(rt[a[x+1]],1,n,x+1,-1);
    			change(rt[a[x+1]],1,n,x  , 1);
    			a[x]^=a[x+1]^=a[x]^=a[x+1];
    		}
    	}
    	return 0;
    }
    

    $100\%$算法:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,a[300001];
    vector<int> v[300001];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		v[a[i]].push_back(i);
    	}
    	while(m--)
    	{
    		int opt;
    		scanf("%d",&opt);
    		if(opt==1)
    		{
    			int l,r,c;
    			scanf("%d%d%d",&l,&r,&c);
    			printf("%d
    ",upper_bound(v[c].begin(),v[c].end(),r)-lower_bound(v[c].begin(),v[c].end(),l));
    		}
    		else
    		{
    			int x;
    			scanf("%d",&x);
    			if(a[x]!=a[x+1])
    			{
    				(*lower_bound(v[a[x]].begin(),v[a[x]].end(),x))++;
    				(*lower_bound(v[a[x+1]].begin(),v[a[x+1]].end(),x+1))--;
    				swap(a[x],a[x+1]);
    			}
    		}
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    SSP状态寄存器SSPSTAT
    【PIC学习第18例】PIC16F877A 内部EEPROM读写实验
    批量去除flv专辑的片头
    .Net并行库介绍——Task(1)
    一个下载游戏封面的站点
    一个猜数字的小游戏
    RamDisk加速Windows 7?
    .Net并行库介绍——Task(2)
    数独的自动出题算法
    Live Messenger 2009登陆错误的解决方法
  • 原文地址:https://www.cnblogs.com/wzc521/p/11295908.html
Copyright © 2020-2023  润新知