「NOIP2021模拟赛8.27 C」正义之名(dusk)

题面

题面描述

给定一个长度为$n$的序列$a_{1∼n}$。

$q$次询问,每次给出一个区间$[l,r]$,要求找出$[l,r]$的一个子区间$[l′,r′]$,满足它不包含$[l,r]$中所有种类的数,且它的长度$r′−l′+1$最大。你只需输出这个最大长度。

特别提醒,$[l′,r′]$可以是长度为$0$的空区间。

输入格式

第一行一个正整数$n$。

接下来一行$n$个正整数$a_{1∼n}$。

随后一行一个正整数$q$。

接下来$q$行,每行两个正整数$l,r$表示一个询问区间。

输出格式

共$q$行,每行一个整数表示答案。

样例一

input

5
1 3 2 3 4
4
2 4
1 3
2 5
1 1

output

1
2
3
0

数据范围与约定

Subtask1(20%):$n,q≤100$

Subtask2(20%):$n≤10^3$

Subtask3(20%):保证数据随机

Subtask4(20%):$n≤2×10^5$

Subtask5(20%):无特殊限制

对于100%的数据,$1≤n,q,a_i≤2×10^6$

题解

分别考虑不选择某种数的情况,则要么选择它在这个区间内相邻两次出现之间的部分,要么选择左端点到它在这个
区间内首次出现的部分,要么选择它在这个区间内最后出现到右端点的部分。
我们离线处理这个问题。事先预处理出$pre_i,nxt_i$ 表示与$a_i$相同的元素上一次/下一次出现的位置。
对于相邻两次出现,可以用$i-pre_i-1$计算,枚举右端点求$i<=r$的贡献,要求满足$pre_i>=l$ ,直接以$pre_i$为下标
用树状数组维护即可。
对于首次出现,同样枚举右端点求$i<=r$的贡献,要求满足$pre_i<l$,以$pre_i$为下标用树状数组维护出$i$的最大值。
对于最后出现只要枚举左端点,也是类似的处理。

我的话没有处理$nxt$,把数组翻转以后对$l,r$处理了一下然后清空前后缀最大值树状数组(注意从$1$开始,所以下标要加$1$)然后再做了一遍求最大值。

代码

#pragma GCC optimize(2)
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define Maxn 2000005
#define lowbit(x) (x&(-x))
using namespace std;
struct IO{
    static const int S=1<<21;
    char buf[S],*p1,*p2;int st[105],Top;
    ~IO(){clear();}
    inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
    inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
    inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='r');return *this;}
    template<typename T>inline IO&operator >> (T&x){
        x=0;bool f=0;char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
        while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
        f?x=-x:0;return *this;
    }
    inline IO&operator << (const char c){pc(c);return *this;}
    template<typename T>inline IO&operator << (T x){
        if(x<0) pc('-'),x=-x;
        do{st[++st[0]]=x%10,x/=10;}while(x);
        while(st[0]) pc('0'+st[st[0]--]);return *this;
    }
}fin,fout;
struct que{int l,r,id,ans;}t[Maxn];
int q,n,a[Maxn],wz[Maxn],pre[Maxn],c1[Maxn],c2[Maxn];
inline bool cmp1(que a,que b){return a.r<b.r;}
inline bool cmp2(que a,que b){return a.id<b.id;}
inline void add1(int i,int x){i++;while (i<=n+1) c1[i]=max(c1[i],x),i+=lowbit(i);}
inline int get1(int i){int res=0;i++;while (i) res=max(res,c1[i]),i-=lowbit(i);return res;}
inline void add2(int i,int x){i++;while (i<=n+1) c2[i]=max(c2[i],x),i+=lowbit(i);}
inline int get2(int i){i++;int res=0;while (i) res=max(res,c2[i]),i-=lowbit(i);return res;}
int main()
{
	freopen("dusk2.in","r",stdin);
	freopen("dusk.out","w",stdout);
	fin>>n;for (int i=1;i<=n;i++) fin>>a[i],pre[i]=wz[a[i]],wz[a[i]]=i;
	fin>>q;for (int i=1;i<=q;i++) fin>>t[i].l>>t[i].r,t[i].id=i;
	sort(t+1,t+q+1,cmp1);
	int x=1;
	for (int i=1;i<=q;i++)
	{
		while (x<=t[i].r) add1(pre[x],x),add2(n-pre[x],x-pre[x]-1),x++;
		t[i].ans=max(t[i].ans,get1(t[i].l-1)-t[i].l);
		t[i].ans=max(t[i].ans,get2(n-t[i].l));
	}
	memset(wz,0,sizeof(wz));
	memset(pre,0,sizeof(pre));
	memset(c1,0,sizeof(c1));
	memset(c2,0,sizeof(c2));
	reverse(a+1,a+n+1);
	for (int i=1;i<=n;i++) pre[i]=wz[a[i]],wz[a[i]]=i;
	for (int i=1;i<=q;i++) t[i].l=n-t[i].l+1,t[i].r=n-t[i].r+1,swap(t[i].l,t[i].r);
	sort(t+1,t+q+1,cmp1);
	x=1;
	for (int i=1;i<=q;i++)
	{
		while (x<=t[i].r) add1(pre[x],x),add2(n-pre[x],x-pre[x]-1),x++;
		t[i].ans=max(t[i].ans,get1(t[i].l-1)-t[i].l);
		t[i].ans=max(t[i].ans,get2(n-t[i].l));
	}
	sort(t+1,t+q+1,cmp2);
	for (int i=1;i<=q;i++) fout<<t[i].ans<<'\n';
	return 0;
}
暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇