Luogu P5070 [Ynoi2015]即便看不到未来

回坑做ynoi,然后发现自己的脑子就是一团浆糊

首先仔细阅读题目,我们发现由于是对于询问的区间先排序后在讨论(刚开始看错了以为不可做题),所以显然可以离线一波

把询问按右端点从小到大排,每次加入右边的位置然后询问左端点的答案

考虑加入一个数之后的贡献,容易发现有四种:

  1. 这个数不和之前的任何数相邻,单独加上$1$的贡献
  2. 这个数在一边和之前的数相邻,要把原来的贡献减$1$然后加上现在$1$的贡献
  3. 这个数在两边都和其他数相邻,把两边的贡献都减了然后加上这一段长的
  4. 这个数以前出现过了,那么只处理从上次出现位置到当前位置的贡献变化

然后我们容易把贡献的影响归为一类,即对于加入的$a_i$,若$(a_i-fr,a_i)\(和\)(a_i,a_i+bk)$均出现过

那么删除$(a_i-fr,a_i)\(和\)(a_i,a_i+bk)\(的贡献然后加入\)(a_i-fr,a_i+bk)$的贡献即可

然后我们发现这个东西和答案都不大好维护的样子,那不是GG

细细一看题目原来查询的区间长度都是$\le 10$的,那么就意味着我们每次只需要暴力扫一遍$(a_i-11,a_i)\(和\)(a_i,a_i+11)$即可进行更新

同理我们也可以直接开$10$个树状数组来维护贡献,具体地直接记录后缀和即可

注意更新贡献的时候要从后往前做才能防止重漏

具体实现详见代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<iostream>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=1e6+5;
struct ques
{
	int l,r,id;
	friend inline bool operator < (const ques& A,const ques& B)
	{
		return A.r<B.r;
	}
}q[N];
struct data
{
	int x,y;
	friend inline bool operator < (const data& A,const data& B)
	{
		return A.x>B.x;
	}
}p[50];
int n,m,mx,tot,a[N],lst[N]; char ans[N][11];
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
		char Fin[S],*A,*B;
	public:
		Tp inline void read(T& x)
		{
			x=0; char ch; while (!isdigit(ch=tc()));
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
		}
		#undef tc
}F;
class TreeArray
{
	private:
		int bit[N];
		#define lowbit(x) (x&-x)
	public:
		inline void add(RI x,CI y)
		{
			for (;x;x-=lowbit(x)) bit[x]+=y;
		}
		inline int get(RI x,int y=0)
		{
			for (;x<=n;x+=lowbit(x)) y+=bit[x]; return y;
		}
		#undef lowbit
}BIT[11];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (F.read(n),F.read(m),i=1;i<=n;++i) F.read(a[i]),mx=max(mx,a[i]);
	for (i=1;i<=m;++i) F.read(q[i].l),F.read(q[i].r),q[i].id=i;
	for (sort(q+1,q+m+1),tot=i=1;i<=n;++i)
	{
		RI cnt=0,j,fr=0,bk=0; for (j=max(1,a[i]-11);j<=min(mx,a[i]+11);++j)
		if (lst[j]>lst[a[i]]) p[++cnt]=(data){lst[j],j}; p[++cnt]=(data){i,a[i]};
		for (p[cnt+1].x=lst[a[i]],sort(p+1,p+cnt+1),j=1;j<=cnt;++j)
		{
			if (p[j].y<a[i]) while (fr<=10&&(a[i]-fr-1==p[j].y||lst[a[i]-fr-1]>p[j].x)) ++fr;
			if (p[j].y>a[i]) while (bk<=10&&(a[i]+bk+1==p[j].y||lst[a[i]+bk+1]>p[j].x)) ++bk;
			if (1<=fr&&fr<=10) BIT[fr].add(p[j].x,-1),BIT[fr].add(p[j+1].x,1);
			if (1<=bk&&bk<=10) BIT[bk].add(p[j].x,-1),BIT[bk].add(p[j+1].x,1);
			if (fr+bk+1<=10) BIT[fr+bk+1].add(p[j].x,1),BIT[fr+bk+1].add(p[j+1].x,-1);
		}
		lst[a[i]]=i; while (tot<=m&&q[tot].r==i)
		{ for (j=1;j<=10;++j) ans[q[tot].id][j]=BIT[j].get(q[tot].l)%10+48; ++tot; }
	}
	for (i=1;i<=m;++i) puts(ans[i]+1); return 0;
}
posted @ 2020-05-10 21:21  空気力学の詩  阅读(156)  评论(0编辑  收藏  举报