zoukankan      html  css  js  c++  java
  • P3901 【数列找不同】

    这个题我们可以使用树状数组做

    啥? 树状数组? 那个不是维护前缀和的东西吗?

    各位看官,让我慢慢道来。


    首先我们可以想到,对于一个询问$ [l,r] (,只有)[1,r]$中的数可能对这个询问有影响。

    这就启示我们可以按照询问的右端点进行一波升序排序。

    不过这和树状数组有什么关系呢?

    对于同一个数(x),假设他在([1,r]) 出现了若干次。

    对于我们的询问([l,r])来说,只有最靠近(r)(x)才最有可能影响到右端点为(r)的询问。

    所以,我们就只用记录最靠近(r)(x)的位置就行了。


    那么我们怎么查询一个区间中不同的个数呢?

    上文说道,我们只用记录最靠近当前右端点的每个数的位置了。

    我们用一个树状数组维护一下。

    树状数组中每一个位置就是输入中每一个数的位置。

    对于一个数(x),他靠近我们当前遍历的右端点的最近一个位置,所对应的树状数组中的数值为1。不是最近的统统为0。

    这样的话。对于一个询问([l,r]),我们计算一下树状数组中([l,r])中的和。如果和是 ((r-l+1))的话,就说([l,r])中所有数都是最靠近(r)的,如果不是的话.则说明有重复出现的。


    真·凭直觉做题(@某月月赛T1)滑稽。我才不会告诉你我是太蒟蒻了导致什么都不会然后来刷黄题的吗?


    类似的题目[SDOI2009]HH的项链](https://www.luogu.org/problemnew/show/P1972)

    这个题被某姓毒名瘤字cz的人加强过(暗地%一%),普通莫队会被卡

    //Lance1ot
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    struct node//树状数组
    {
    	int data[101000];
    	int num;
    	void updata(int pos,int value)
    	{
    		while(pos<=num&&pos)
    		{
    			data[pos]+=value;
    			pos+=(pos&(-pos));
    		}
    		return ;
    	}
    	int sum(int pos)
    	{
    		int res=0;
    		while(pos)
    		{
    			res+=data[pos];
    			pos-=(pos&(-pos));
    		}
    		return res;
    	}
    	int check(int l,int r)
    	{
    		return sum(r)-sum(l-1);
    	}
    };
    node bit;
    struct Query
    {
    	int l;
    	int r;
    	int num;
    }q[101000];//询问
    bool compare(const Query &a,const Query &b)
    {
    	return a.r<b.r;
    }
    int data[101000];//原数组
    int ans[101000];
    int last[101000];//最近一次出现的位置
    int main()
    {
    	int n,m;
    	scanf("%d%d",&n,&m);
    	bit.num=n;
    	for(int i=1;i<=n;i++)
    		scanf("%d",&data[i]);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&q[i].l,&q[i].r);
    		q[i].num=i;//离线处理,是第几个询问。
    	}
    	sort(q+1,q+1+m,compare);//排序
    	int Q=1;
    	for(int i=1;i<=n;i++)
    	{
    		bit.updata(last[data[i]],-1);//撤销上一个记录
    		bit.updata(i,1);//更新
    		last[data[i]]=i;//保存
    		while(q[Q].r==i&&Q<=m)//判断当前右端点是否和某个重合
    		{
    			if(bit.check(q[Q].l,q[Q].r)==(q[Q].r-q[Q].l+1))//因为是离线算法(fa♂),所以要保存答案
    				ans[q[Q].num]=1;
    			else
    				ans[q[Q].num]=0;
    			Q+=1;//写成while保险
    		}
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(ans[i]==1)
    			printf("Yes
    ");
    		else
    			printf("No
    ");
    	}
    	return 0;
    }
    

    速度还算可以吧。

  • 相关阅读:
    Linux写时拷贝技术(copy-on-write)
    crontab使用进程锁解决冲突
    Better Linux Disk Caching & Performance with vm.dirty_ratio & vm.dirty_background_ratio
    精确度量Linux下进程占用多少内存的方法
    在Linux系统的服务器上使用Memtester进行内存压力测试
    How to speed up insertion performance in PostgreSQL
    Mongo的备份和恢复(mongodump 和mongorestore )
    MongoDB:删除操作
    MongoDB插入数据的3种方法
    Centos 软连接和硬链接
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/9062420.html
Copyright © 2011-2022 走看看