1 条题解

  • 0
    @ 2025-8-24 21:56:38

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar wangjyqh
    **

    搬运于2025-08-24 21:56:38,当前版本为作者最后更新于2018-09-19 17:12:42,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    提供一个按照右端点排序的思路(类比hh的项链)

    回顾hh的项链,我们使用离线+树状数组,和last[j]表示上一次出现j的位置,对于第p个的数j,我们add(last[j],-1),add(p,1),因为我们按照r排序,只用管最右边的一个,所以留下最右端的就可以,对于一个询问直接树状数组求区间和;

    比较一下这两道题的区别,同样是计算颜色不同的数量,但是这道题目要求只有存在两个相同颜色这个颜色才做出贡献,怎么办呢?

    我们维护两个东西,last1[j]表示上上次出现j的位置,last2[j]表示上次出现的位置

    对于第p个的数j

    第一次出现j时没有用,我们直接记录last1=p;

    第二次出现j时,他就会产生代价,但值得注意的是我们不应该在第二次出现j的为位置上+1,而是在上一次出现的位置last1上+1,这是因为我们按照r从小到大排序,比如2,2,3这个序列,如果我们在第二次出现2的位置上+1,变成(0,1,0),当询问[2,3]就不对了,应该在倒数第二次出现的位置+1变成(1,0,0);

    两次以上出现,我们只需要在倒数第2次的位置上+1,其他位置上出现j全部为零,实现:add(last1[j],-1);add(last2[j],1),last1=last2,last2=j;

    扩展:如果将题目的限制改一改变成有n个颜色同时在询问区间,我们我们可以仍按照r递增排序,维护last1,last2,~~,lastn;让倒数第n次的位置上+1,其他出现j的位置上全是0

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    struct node
    {
    	int l,r,pos;
    }t[2000010];
    int last1[2000010],last2[2000010],c[2000010],a[2000010],ans[2000010];
    int n,q,m;
    inline bool cmp(node A,node B){
       return A.r<B.r;
    }
    inline void add(int x,int val){
        for(int i=x;i<=n;i+=(i&-i))c[i]+=val;
    }
    inline int query(int x){
        int ans=0;
        for(int i=x;i;i-=(i&-i))ans+=c[i];
        return ans;
    }
    int main(){
        scanf("%d%d%d",&n,&q,&m);
        for(int i=1;i<=n;++i)scanf("%d",&a[i]);
        for(int i=1;i<=m;++i){
           scanf("%d%d",&t[i].l,&t[i].r);
           t[i].pos=i;
        }
        sort(t+1,t+m+1,cmp);
        int j=1;
        for(int i=1;i<=m;++i){
        	for(;j<=t[i].r;++j){
               if(!last1[a[j]])last1[a[j]]=j;
               else {
               	  if(!last2[a[j]]){
               	  	add(last1[a[j]],1);
                    last2[a[j]]=j;
               	  }else {
               	  	 add(last2[a[j]],1);
               	  	 add(last1[a[j]],-1);
               	  	 last1[a[j]]=last2[a[j]];
               	  	 last2[a[j]]=j;
               	  } 
               }
        	}
        	ans[t[i].pos]=query(t[i].r)-query(t[i].l-1);
        }
        for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
        return 0;
    }
    
    • 1

    信息

    ID
    3051
    时间
    2000ms
    内存
    500MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者