【YNOI2015】【洛谷P5070】即便看不到未来(相当暴力)(树状数组)

传送门


题解:

好奇怪啊这题居然在我的日推里面,MD,YNOI,我像是那么毒瘤的人吗?

不过来都来了,就还是写了一下。

询问离线,按照右端点排序。

考虑一个位置一个位置地从左向右加入新的数。

发现在第 i i i个位置加入的数能够产生的贡献,显然它只能更新满足以下条件的区间的答案:

  1. 左端点在这个数上一次出现的位置之后,显然上一次出现的位置之前的区间已经包含了它,排序去重之后不改变答案。
  2. 点的值与这个位置上的差不超过11,由于输出格式告诉我们不需要计算长度大于10的答案,更新的时候要弄到11是因为我们需要考虑原来长度为10的区间长度变成11。

我们把所有满足上面限制的端点提取出来。按照位置从后向前加入,考虑加入的数此时对答案的影响。

很显然是将某个长度为 l e n len len的区间第一次出现的位置向前提前了,利用差分数组可以方便地维护。

而我们需要快速修改和询问差分数组,很自然就用上了树状数组。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
	}
	
	template<typename T>
	inline T get(){
		char c;
		while(!isdigit(c=gc()));T num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int getint(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;
using pii=std::pair<int,int>;
#define fi first
#define se second 

cs int N=1e6+6;

int n,m,a[N],last[N];
int ans[N][11];
bool tag[N];

std::vector<pii> q[N],vec;

int tr[11][N];

inline void modify(int t,int pos,int d){
	for(;pos;pos^=pos&-pos)tr[t][pos]+=d;
}

inline void query(int pos,int *ans){
	for(;pos<=n;pos+=pos&-pos)
	for(int re i=1;i<=10;++i)ans[i]+=tr[i][pos];
}

signed main(){
//	freopen("future.in","r",stdin);
	n=getint(),m=getint();
	for(int re i=1;i<=n;++i)a[i]=getint();
	for(int re i=1;i<=m;++i){
		int l=getint(),r=getint();
		q[r].push_back(pii(l,i));
	}
	for(int re i=1;i<=n;++i){
		vec.clear();
		int v=a[i],mn=std::max(1,v-11),mx=std::min(v+11,N-6); 
		for(int re j=mn;j<=mx;++j)
		if(last[j]&&last[j]>last[v])vec.push_back(pii(last[j],j));
		vec.push_back(pii(last[v],-1));
		vec.push_back(pii(i,v));
		std::sort(vec.rbegin(),vec.rend());
		tag[v]=1;
		for(int re i=0;i<vec.size()-1;++i){
			int l=0,r=0;
			if(~vec[i].se)tag[vec[i].se]=1;
			while(l<=10&&tag[v-l-1])++l;
			while(r<=10&&tag[v+r+1])++r;
			int t=l+r+1;
			if(l&&l<=10)modify(l,vec[i].fi,-1),modify(l,vec[i+1].fi,1);
			if(r&&r<=10)modify(r,vec[i].fi,-1),modify(r,vec[i+1].fi,1);
			if(t&&t<=10)modify(t,vec[i].fi,1),modify(t,vec[i+1].fi,-1);
		}
		tag[v]=0;
		for(pii &p:vec)(~p.se)&&(tag[p.se]=0);
		for(pii &p:q[i])query(p.fi,ans[p.se]);
		last[v]=i;
	}
	for(int re i=1;i<=m;++i){
		for(int re j=1;j<=10;++j)putchar('0'+ans[i][j]%10);
		putchar('\n');
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值