【模拟赛】artist

题解

image

经典题。对于查询颜色,记录每个下标的上一个与他颜色相同的位置,则一个区间内颜色互不相同当且仅当:

\(\max(lst[i]|l\le i\le r)<l\)。这个用线段树维护一下即可。

在线维护。考虑对于单点颜色 \((x,y)\) 修改,建出一个链表,让 \(lst[nxt[x]]=lst[x]\)\(nxt[lst[x]]=nxt[x]\),同时更改线段树,实现对 \(x\) 的删除。在把 \(y\) 颜色插入链表时,由于不知道 \(x\) 的上一个颜色为 \(y\) 的位置,于是用 \(set\) 维护一下每种颜色的所有位置,询问时upper_bound即可。

注意到这样一段话,保证任何两个区间都是不相交或包含的关系。于是这是一个树形结构,被包含的小区间满足时大区间才能满足,于是直接建树。考虑到原本满足的小区间可能在后期变得不满足,要是把树回退的话时间复杂度可能要炸。发现只要求第一次满足条件的时候,后期不满足了也没影响,可以先把叶子节点丢到 \(set\) 中,修改时若叶子被删完,再把父亲加到 \(set\) 中即可。

code

#include<bits/stdc++.h>
using namespace std;
const int N=5e5;
int n,m,q,c[N+5],ans[N+5],L[N+5],R[N+5];
int nxt[N+5],tmp[N+5],lst[N+5],fa[N+5];
int mx[4*N+5],du[N+5],val,rev[N+5];
struct node {int  l,r,id;} p[N+5],sta[N+5];
bool operator < (const node p,const node q) {return p.l==q.l?p.r>q.r:p.l<q.l;}
set<int> clo[N+5];set<node> s;
void build(int k,int l,int r)
{
	if(l==r) return mx[k]=lst[l],void();
	int mid=(l+r)>>1;build(k*2,l,mid);build(k*2+1,mid+1,r);
	mx[k]=max(mx[k*2],mx[k*2+1]);
}
int ask(int k,int l,int r,int x,int y)
{
	if(x>r||y<l) return 0;
	if(x<=l&&r<=y) return mx[k];
	int mid=(l+r)>>1;
	return max(ask(k*2,l,mid,x,y),ask(k*2+1,mid+1,r,x,y)); 
}
void update(int k,int l,int r,int x,int v)
{
	if(l==r) return mx[k]=v,void();
	int mid=(l+r)>>1;
	if(x<=mid) update(k*2,l,mid,x,v);
	else update(k*2+1,mid+1,r,x,v);
	mx[k]=max(mx[k*2],mx[k*2+1]);
}
void change(int x,int y)
{
	if(nxt[x]) update(1,1,n,nxt[x],lst[x]);
	nxt[lst[x]]=nxt[x];lst[nxt[x]]=lst[x],clo[c[x]].erase(x),c[x]=y;
	auto it=clo[y].upper_bound(x);lst[x]=nxt[x]=0;
	if(it!=clo[y].end()) nxt[x]=*it,update(1,1,n,nxt[x],x);
	if(it!=clo[y].begin()) --it,lst[x]=*it;
	clo[y].insert(x);nxt[lst[x]]=x;lst[nxt[x]]=x;
	update(1,1,n,x,lst[x]);
}
void solve(int x,int tim)
{
	if(ask(1,1,n,L[x],R[x])<L[x])
	{
		s.erase(node{L[x],R[x],x}),ans[x]=tim;
		if(fa[x]&&!(--du[fa[x]])) du[fa[x]]=-1,s.insert(p[rev[fa[x]]]),solve(fa[x],tim);
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1; i<=n; i++)
	{
		scanf("%d",&c[i]);
		lst[i]=tmp[c[i]],nxt[lst[i]]=i;
		tmp[c[i]]=i;clo[c[i]].insert(i);
	}
	build(1,1,n);
	for(int i=1; i<=m; i++) scanf("%d%d",&p[i].l,&p[i].r),ans[i]=m+i,p[i].id=i,L[i]=p[i].l,R[i]=p[i].r;
	sort(p+1,p+1+m);
	int top=0;
	for(int i=1; i<=m; i++)
	{
		if(p[i].l==p[i].r||ask(1,1,n,p[i].l,p[i].r)<p[i].l) {ans[p[i].id]=0;du[p[i].id]=-1;continue;}
		rev[p[i].id]=i;while(top&&sta[top].r<p[i].l) --top;
		fa[p[i].id]=sta[top].id,sta[++top]=p[i];++du[fa[p[i].id]];
	}
	for(int i=1; i<=m; i++) if(!du[p[i].id]) s.insert(p[i]);
	for(int i=1; i<=q; i++)
	{
		int x,y;scanf("%d%d",&x,&y);
		change(x,y);
		auto it=s.upper_bound(node{x,0,0});
		if(it!=s.begin()) --it,solve((*it).id,i);
	}
	for(int i=1; i<=m; i++) val^=ans[i];printf("%d\n",val);
	return 0;
}
posted @ 2021-11-09 09:20  keepcoder  阅读(47)  评论(1编辑  收藏  举报