zoukankan      html  css  js  c++  java
  • BZOJ1878 [SDOI2009]HH的项链 树状数组 或 莫队

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1878


    题意概括

      给出一个长度为n的序列,用m次询问,问区间Li~Ri中有多少种不同的数。

      0<=数值<=1000000,n<=50000,m<=200000


    题解

      本题有许多做法。

      这里介绍树状数组和莫队,都是离线算法。

      树状数组

      我们把序列按照R从小到大排序。

      然后从左往右走。

      依次加入数字,当前的状态,比如说搞定了前i个数字。

      对于第i+1个数字,我们要给它做一个标记,但是不可以重复,那么最优的方案就是把它之前的那个位置的+1标记删除,放到这里来。

      于是对于搞定前i个数的时候,有且一定有对于某一个数值,如果它出现过,那么它的+1标记在最后出现的那个地方。

      为什么可以?因为R是递增的!

      然后就是维护一个点修改和区间和的东西了。秒选树状数组。

      莫队

      莫队就是最裸的莫队。

      先把1~n的区间尽量平均的分成sqrt(n)块。

      把所有的询问以L所在的块为第一关键字升序,R为第二关键字升序排序。

      然后就是大暴力。

      朴素的写法有点长。

      但是压缩之后短的无厘头……


    代码

      代码1 - 树状数组

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=50000+5,M=200000+5,V=1000000+5;
    int n,m,a[N],c[N],pos[V];
    struct Query{
    	int L,R,bh,ans;
    	bool operator < (const Query x) const {
    		return R<x.R;
    	}
    }q[M];
    bool cmpbh(Query a,Query b){
    	return a.bh<b.bh;
    }
    int lowbit(int x){
    	return x&-x;
    }
    void add(int x,int d){
    	if (!x)
    		return;
    	for (;x<=n;x+=lowbit(x))
    		c[x]+=d;
    }
    int sum(int x){
    	int ans=0;
    	for (;x>0;x-=lowbit(x))
    		ans+=c[x];
    	return ans;
    }
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	scanf("%d",&m);
    	for (int i=1;i<=m;i++){
    		scanf("%d%d",&q[i].L,&q[i].R);
    		q[i].bh=i;
    	}
    	sort(q+1,q+m+1);
    	memset(pos,0,sizeof pos);
    	memset(c,0,sizeof c);
    	for (int i=1,j=0;i<=m;i++){
    		while (j<q[i].R){
    			j++;
    			add(pos[a[j]],-1);
    			pos[a[j]]=j;
    			add(pos[a[j]],1);
    		}
    		q[i].ans=sum(q[i].R)-sum(q[i].L-1);
    	}
    	sort(q+1,q+m+1,cmpbh);
    	for (int i=1;i<=m;i++)
    		printf("%d
    ",q[i].ans);
    	return 0;
    }
    

      代码2 - 莫队

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=50000+5,M=200000+5,V=1000000+5;
    int n,m,size,a[N],cnt[V];
    struct Query{
    	int L,R,bh,ans;
    }q[M];
    bool cmpmd(Query a,Query b){
    	int k1=a.L/size,k2=b.L/size;
    	if (k1!=k2)
    		return k1<k2;
    	return a.R<b.R;
    }
    bool cmpbh(Query a,Query b){
    	return a.bh<b.bh;
    }
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	scanf("%d",&m);
    	for (int i=1;i<=m;i++){
    		scanf("%d%d",&q[i].L,&q[i].R);
    		q[i].bh=i;
    	}
    	size=sqrt(n)+0.5;
    	memset(cnt,0,sizeof cnt);
    	sort(q+1,q+m+1,cmpmd);
    	for (int i=1,tot=0,L=1,R=0;i<=m;i++){
    		while (R<q[i].R){
    			R++;
    			if (cnt[a[R]]==0)
    				tot++;
    			cnt[a[R]]++;
    		}
    		while (L>q[i].L){
    			L--;
    			if (cnt[a[L]]==0)
    				tot++;
    			cnt[a[L]]++;
    		}
    		while (R>q[i].R){
    			cnt[a[R]]--;
    			if (cnt[a[R]]==0)
    				tot--;
    			R--;
    		}
    		while (L<q[i].L){
    			cnt[a[L]]--;
    			if (cnt[a[L]]==0)
    				tot--;
    			L++;
    		}
    		q[i].ans=tot;
    	}
    	sort(q+1,q+m+1,cmpbh);
    	for (int i=1;i<=m;i++)
    		printf("%d
    ",q[i].ans);
    	return 0;
    }
    

      代码3 - 莫队+代码压缩

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=50000+5,M=200000+5,V=1000000+5;
    int n,m,size,a[N],cnt[V];
    struct Query{
    	int L,R,bh,ans;
    }q[M];
    bool cmpmd(Query a,Query b){
    	int k1=a.L/size,k2=b.L/size;
    	if (k1!=k2)
    		return k1<k2;
    	return a.R<b.R;
    }
    bool cmpbh(Query a,Query b){
    	return a.bh<b.bh;
    }
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	scanf("%d",&m);
    	for (int i=1;i<=m;i++)
    		scanf("%d%d",&q[i].L,&q[i].R),q[i].bh=i;
    	size=sqrt(n)+0.5;
    	memset(cnt,0,sizeof cnt);
    	sort(q+1,q+m+1,cmpmd);
    	for (int i=1,tot=0,L=1,R=0;i<=m;i++){
    		while (R<q[i].R)
    			tot+=cnt[a[++R]]++==0;
    		while (L>q[i].L)
    			tot+=cnt[a[--L]]++==0;
    		while (R>q[i].R)
    			tot-=--cnt[a[R--]]==0;
    		while (L<q[i].L)
    			tot-=--cnt[a[L++]]==0;
    		q[i].ans=tot;
    	}
    	sort(q+1,q+m+1,cmpbh);
    	for (int i=1;i<=m;i++)
    		printf("%d
    ",q[i].ans);
    	return 0;
    }
    

      

  • 相关阅读:
    hdu1069Monkey and Banana(动态规划)
    hdu2571 命运(动态规划)
    hdu1505City Game(动态规划)
    在jvm底层有关于方法区的介绍
    用IDEA查看源码总是跳到.class文件而不是.java文件的解决办法
    如果Son类继承Father类,Father类继承GrandFather类,那么new Son()创建对象的时候是否会执行GrandFather类里面的方法
    看面试题有感:子类构造器(无参或有参)继承的super()方法在何时调用,与静态代码块,普通代码块相比的执行顺序如何的思考及证明
    关于子类构造器调用super()方法的规定
    为什么重写了equals方法后还需要重写hashCode方法
    字符串常量池处在JVM的堆中,那么是在堆的哪个部分呢
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1878.html
Copyright © 2011-2022 走看看