1 条题解

  • 0
    @ 2025-8-24 22:34:09

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar FjswYuzu
    Rainybunny狂热粉丝!111111 | Last Goodbye

    搬运于2025-08-24 22:34:09,当前版本为作者最后更新于2022-09-02 20:17:19,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    比较简单的序列维护题。

    没说在线就先离线扫描线。假设我们现在扫到了 rr,我们要对每一个 ll 维护出一个 plp_l 表示 [l,pl][l,p_l][l,r][l,r] 的一个合法子区间且 plp_l 最小。

    现在考虑动态维护这个 pp 啊。现在我们加入了一个 wiw_i,上一次出现的位置为 cc,那么 [c+1,i][c+1,i] 这些数都需要包含到 ii 才合法。这个可以区间打标记。

    接下来思考查询怎么实现。现在扫描到了 rr,处理询问 [l,r][l,r]。我们需要找到最大的 cc 满足 [c,r][c,r][l,r][l,r] 的合法子区间,答案就是 i[l,c],piii \in [l,c], p_i-i 的最小值。

    首先如果知道这个区间的话我们就可以直接使用线段树维护区间最小值,然后区间打标记解决查询的问题。现在问题来到了怎么找这个 cc 上。

    有很简单的 O(nlogn)O(n \log n) 的维护方法。考虑一些接近线性的方法吧。开一个并查集,扫描线的时候维护并查集上每个结点 ll 的根 cc 表示 [c,r][c,r][l,r][l,r] 的合法子区间且 cc 最大。

    这个东西怎么维护呢?注意到在加入 wiw_i 的时候,记其上一次出现的位置为 cc,那么就不再需要 cc 这个位置了,那么就把并查集上结点 cc 连向结点 c+1c+1 即可。

    那么找到这个 cc 就只需要一个简单的并查集查询。问题解决了。

    时间复杂度 O(nlogn)O(n \log n)。存在 O(nloglogn)O(n \log \log n) 的做法。

    int minn[8000005],tag[8000005];
    inline void push_up(int now){minn[now]=min(minn[lc(now)],minn[rc(now)]);}
    inline void push_down(int now,int l,int r)
    {
    	if(tag[now])
    	{
    		tag[lc(now)]=tag[rc(now)]=tag[now];
    		Mm;
    		minn[lc(now)]=tag[now]-mid+1,minn[rc(now)]=tag[now]-r+1;
    		tag[now]=0;
    	}
    }
    void modify(int l,int r,int now,int x,int y,int c)
    {
    	if(x<=l && r<=y)
    	{
    		tag[now]=c;
    		minn[now]=c-r+1;
    		return ;
    	}
    	push_down(now,l,r);
    	Mm;
    	if(x<=mid)	modify(l,mid,lc(now),x,y,c);
    	if(mid<y)	modify(mid+1,r,rc(now),x,y,c);
    	push_up(now);
    }
    int query(int l,int r,int now,int x,int y)
    {
    	if(x<=l && r<=y)	return minn[now];
    	push_down(now,l,r);
    	Mm,ret=1e9;
    	if(x<=mid)	ret=min(ret,query(l,mid,lc(now),x,y));
    	if(mid<y)	ret=min(ret,query(mid+1,r,rc(now),x,y));
    	return ret;
    }
    struct unionFindSet{
    	int fa[2000005];
    	void makeSet(int up){for(int i=0;i<=up;++i)	fa[i]=i;}
    	int findSet(int x){return x==fa[x]?x:fa[x]=findSet(fa[x]);}
    	int& operator [] (int x){return fa[x];}
    }ufs;
    #define mp make_pair
    vector<pair<int,int>> qry[2000005];
    int n,a[2000005],ans[2000005];
    int lst[2000005];
    int main(){
    	n=read();
    	for(int i=1;i<=n;++i)	a[i]=read();
    	ufs.makeSet(n);
    	int q=read();
    	for(int i=1;i<=q;++i)
    	{
    		int l=read(),r=read();
    		qry[r].push_back(mp(l,i));
    	}
    	for(int i=1;i<=n;++i)
    	{
    		modify(1,n,1,lst[a[i]]+1,i,i);
    		if(lst[a[i]])	ufs[lst[a[i]]]=lst[a[i]]+1;
    		lst[a[i]]=i;
    		for(auto st:qry[i])
    		{
    			int l=st.first,r=ufs.findSet(l);
    			ans[st.second]=query(1,n,1,l,r);
    		}
    	}
    	for(int i=1;i<=q;++i)	write(ans[i]),puts("");
    	return 0;
    }
    
    • 1

    信息

    ID
    7100
    时间
    3000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者