zoukankan      html  css  js  c++  java
  • LuoguP1972书架

    其实我对树状数组及一系列据结构掌握一直如同菜鸟

    打了这么久连别人认为是模板的题都想不出来

    所以我采用题海战术,妄想有些突破

    题目链接


    本题的意思是选取随机一段l~r的区间,询问这个区间里有多少种不同贝壳。

    本来看到区间统计两个词语就应该想到树状数组&线段树

    但是仔细一想,如果是线段树的合并,必须满足相加的性质(例如数量,长度等)或者一些可以“拼接的东西”(例如hash值,相同颜色小球的数量等……)这些便可以用线段树的合并。

    而现在是统计种类的多少,显然不能用普通的合并(1,3,5)&(1,4,5) 你总不能说合并后种类为3+3==6种吧(显然是4种)

    重点来了

    重点来了

    终点来了

    那我们怎么统计种类的多少呢?

    仔细分析一下题目性质,要求我们求l~r之间种类数量,如果我们普通的模板解决不了怎么办?

    我们假设我们求的是1~l,我们会怎么求

    这个时候思路应该就会比较明显,但是还是没有到想出来的地步(所以没想出来的朋友们不要慌)

    我们直接for循环过去,用一个vis数组保存,如果碰到一个数x,!vis[x],那么我们的ans++;(ans代表的是颜色种类)

    如果vis[x]>0 ,那我们就直接continue; 对不对?

    那么代码如下:

    (```)

    for(register int i=l;i<=r;i++){
        if(!vis[color[i]]) vis[color[i]]=true,ans++;
        //color[i]代表的是i号数字的种类
    }
    

    (```)

    这个时候时间复杂度就是n*m(长度乘以询问数)

    想不到更好的算法怎么办?

    那就优化噻!

    我们依据我们算法的思想——本质上是统计出现的种类,重复的舍去,而我们要求的lr又自然地想到1l 和 1~r两个区间,那么我们冥思苦想,怎么才能用区间表示呢

    我们将集合S代表1~l-1 & lr两个区间公有的元素,那么我们可以只选择1l-1的元素++,或者只选择lr的元素++;我们要统计lr,那么我们理所应当加在l~r上:

    将其通俗一点,便是在循环遍历时,if(vis[color[i]]) 上一个color[i]的位置--;i++;

    这个时候便可以用树状数组统计。

    而区间的话我们可以离线处理,因为1l这个初始点并不能包含这个lr,所以说我们按照r的大小排序,这样上一个color[i]--时,就不会影响答案

    所以完整的代码如下

    (```)

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define Starseven main
    #define ri register int
    using namespace std;
    const int N=1e6+20;
    int n,m,cnt[N],before[N],tr[N];
    
    struct node{
        int kind,loc;
    }num[N];
    
    struct noe{
        int ans,l,r,id;
    }area[N];
    
    bool cmp(const node &a,const node &b){
        if(a.kind!=b.kind) return a.kind<b.kind;
        else return a.loc<b.loc;
    }
    
    bool fuck(const noe &a,const noe &b){
        return a.r<b.r;
    }
    
    void Insert(int x,int va){
        for(ri i=x;i<=n;i+=i&-i) tr[i]+=va;
    }
    
    int Getsum(int x){
        int re=0;
        for(ri i=x;i;i-=i&-i) re+=tr[i];
        return re;
    }
    
    bool again(const noe &a,const noe &b){
        return a.id<b.id;
    }
    
    int read();
    void write(int); 
    void wrote(int);
    int Starseven(){
        n=read();
        for(ri i=1;i<=n;i++){
        	num[i].loc=i;cnt[i]=num[i].kind=read();	
        }
        sort(num+1,num+1+n,cmp);
        for(ri i=1;i<=n;i++){
        	before[num[i].loc]=num[i].kind==num[i-1].kind?num[i-1].loc:0;
        }
        m=read();
        for(ri i=1;i<=m;i++){
    	area[i].l=read(),area[i].r=read();
    	area[i].id=i;	
        }
        sort(area+1,area+1+m,fuck);
        int tail=1;
        for(ri i=1;i<=n;i++){
    	Insert(i,1);
    	if(before[i]) Insert(before[i],-1);
    	while(area[tail].r==i){
    		area[tail].ans=Getsum(i)-Getsum(area[tail].l-1);
    		tail++; 
    	}
        }
        sort(area+1,area+1+m,again);
        for(ri i=1;i<=m;i++) write(area[i].ans);
        return 0;
    } 
    
    int read(){
    char ch=getchar();int re=0,op=1;
    while(ch<'0'||ch>'9'){
    	if(ch=='-')op=-1;
    	ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
    	re=(re<<3)+(re<<1)+ch-'0';
    	ch=getchar();
    }
    return re*op;
    }
    
    inline void write(int x){
    wrote(x);
    puts("");
    }
    
    inline void wrote(int x)
    {
        if(x<0){
    	    putchar('-');
        	x=-x;
        }
        if(x>9) 
    	wrote(x/10);
        putchar(x%10+'0');
    }
    

    (```)

  • 相关阅读:
    Oracle 推出 ODAC for Entity Framework 和 LINQ to Entities Beta版
    Entity Framework Feature CTP 5系列文章
    MonoDroid相关资源
    MSDN杂志上的Windows Phone相关文章
    微软学Android Market推出 Web Windows Phone Marketplace
    使用 Visual Studio Agent 2010 进行负载压力测试的安装指南
    MonoMac 1.0正式发布
    Shawn Wildermuth的《Architecting WP7 》系列文章
    使用.NET Mobile API即51Degrees.mobi检测UserAgent
    MongoDB 客户端 MongoVue
  • 原文地址:https://www.cnblogs.com/starseven/p/12463353.html
Copyright © 2011-2022 走看看