[HEOI2012] 采花题解报告

                        采花题解

                                                                                                                                            By李宇航


 

树状数组

  首先我们要有离线处理的思想,即把左右端点记录下来,并且记录下来每个问题的pos。然后我们要对右端点升序排序。当然,还有更加重要的预处理操作。

我们要记录每一个位置该种颜色花的上一次出现的位置,用两个数组Front(下标为花的颜色),Prev(下标为位置)即可实现,如果没有出现,则Prev=0;

然后我们就从1-N开始扫了,每一次先是ADD(i)。对于每个i,如果prev[i]=0

那我们没有必要来更新了。我们只对prev[i]存在的更新,令r= prev[i],l=prev[r],那么我们就找到了一个更新的区间,我们将l向下更新-1,将r向下更新+1,于是就完成了去重操作,然后对以该点为右端点的ASK 从左端点GETSUM就可以了


有图有真相 (自己画的,凑合看吧)

   

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010*10;
int Front[maxn],Prev[maxn],c[maxn],data[maxn],Ans[maxn];
 
int N,C,M;
 
int lowbit(int x)
{
	return x&(-x);
}
 
struct node
{
	int pos,l,r;
}A[maxn];
 
bool comp(node a,node b)
{
	
	return a.r<b.r||a.r==b.r&&a.l<b.r;
}
void updata(int x,int data)
{
	for(;x>0;x-=lowbit(x))
	{
		c[x]+=data;
	}
}
int get(int x)
{
	int ans=0;
	for(;x<=N;x+=lowbit(x))
	{
		ans+=c[x];
	}
	return ans;
}
void ADD(int x)
{
	if(!Prev[x])return;
	int r=Prev[x],l=Prev[r];
	updata(r,1);
	if(l)updata(l,-1);
}
int main()
{
	
	scanf("%d%d%d",&N,&C,&M);
	for(int i=1;i<=N;i++)
	{
		scanf("%d",&data[i]);
		Prev[i]=Front[data[i]];
		Front[data[i]]=i;
	}
	for(int i=1;i<=M;i++)
	{
		scanf("%d%d",&A[i].l,&A[i].r);
		A[i].pos=i;
	}
	sort(A+1,A+M+1,comp);
	int ha=1;
	for(int i=1;i<=N;i++)
	{
		ADD(i);
		while(ha<=M&&A[ha].r==i)
		{
			Ans[A[ha].pos]=get(A[ha].l);
			ha++;
		}
	}
	for(int i=1;i<=M;i++)printf("%d\n",Ans[i]);
	
 	return 0;
}


图上解释的是对第三朵颜色相同的花的操作

对于第二颜色相同的花,我们只把他的前驱加向下更新+1即可(所以略去)

所以我们得到对于每朵花 在其前驱(右端点) 和前驱的前驱(左端点)存在的情况下,分别对其进行更新。


题解如有错误,欢迎指正!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值