Loading

3月3日

区分度是人吗???第一210,第二130,然后第40+也有100?

喜提 \(100 + 10 + 1 =111 pts\)

T1

???这放省选第一题?NOIP第二题都不够格。

直接维护向两边分别能跳多远,每次找半径内比当前数大的最小值,简单转移即可。写了颗主席树,复杂度 \(O(n \log n)\)

点击查看代码
#include <bits/stdc++.h>
char *p1,*p2,buf[1<<21];
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
using namespace std;
const int MAXN=5e5+10;
int n,d,a[MAXN],cnt,b[MAXN];
int L[MAXN],R[MAXN],rot[MAXN];
struct tree{
	int cnt;
	int ls,rs;
}t[MAXN*35];
void update(int l,int r,int p,int& rt,int rtr)
{
	t[rt=++cnt]=t[rtr];
	++t[rt].cnt;
	if(l==r) return;
	int m=(l+r)>>1;
	if(p<=m) update(l,m,p,t[rt].ls,t[rtr].ls);
	else update(m+1,r,p,t[rt].rs,t[rtr].rs);
}
int ask(int l,int r,int p,int rt,int rtr)
{
	if(t[rt].cnt-t[rtr].cnt==0) return 0;
	if(l==r) return l;
	int m=(l+r)>>1,ans=0;
	if(m>p) ans=ask(l,m,p,t[rt].ls,t[rtr].ls);
	if(p<r && !ans) ans=ask(m+1,r,p,t[rt].rs,t[rtr].rs);
	return ans;
}
int query(int l,int r,int L,int R,int rt,int rtr)
{
	if(L<=l && r<=R) return t[rt].cnt-t[rtr].cnt;
	int m=(l+r)>>1,ans=0;
	if(L<=m) ans=query(l,m,L,R,t[rt].ls,t[rtr].ls);
	if(m<R) ans+=query(m+1,r,L,R,t[rt].rs,t[rtr].rs);
	return ans;
}
int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x;
}
int main()
{
	n=read(),d=read();
	for(int i=1;i<=n;i++) a[i]=read(),b[a[i]]=i;
	for(int i=1;i<=n;i++) update(1,n,a[i],rot[i],rot[i-1]);
	for(int i=1;i<=n;i++) 
	{
		int l=max(i-d,1)-1;
		int p=ask(1,n,a[i],rot[i],rot[l]);
		if(p)
		{
			L[i]=L[b[p]]+query(1,n,a[i],n,rot[i],rot[b[p]]);
		}
	}
	for(int i=n;i;i--) 
	{
		int r=min(i+d,n);
		int p=ask(1,n,a[i],rot[r],rot[i-1]);
		if(p)
		{
			R[i]=R[b[p]]+query(1,n,a[i],n,rot[b[p]-1],rot[i-1]);
		}
	}
	for(int i=1;i<=n;i++) cout<<L[i]+R[i]+1<<" ";
}

T2

赛时无人场切,且赛后发现 std 锅了,应该不是思路的错。没改。

T3

赛时仅 jmr 场切,很牛的分拆和推广,好像听懂了,没改。

posted @ 2026-03-04 09:20  HD0X  阅读(3)  评论(0)    收藏  举报