题解 CF848C Goodbye Souvenir

题目链接
题意描述

给定一个长为\(n\)的数组,定义一个数在区间\([l,r]\)的权值为这个数最后一次出现下标\(-\)第一次出现下标,要求支持单点修改,区间查询。
\(n,a_i\le10^5\)

\(\large{Solution:}\)
“最后一次-第一次”有一个经典的\(Trick:\)
设出现下标从小到大为\(a_1,a_2…a_k\),则\(a_k-a_1=(a_k-a_{k-1})+(a_{k-1}-a_{k-2})…+(a_2-a_1)\)
于是我们可以维护相邻出现的下标差,求个和就行了。
发现一对下标\(a_i,pre_{a_i}\)计入答案的条件为\([l\le a_i\le r]\wedge[l\le pre_{a_i}\le r]\),所以只要求出每个下标的\(pre\),问题就是一个动态二维数点。
这里链表操作用的\(Treap\)实现,二维数点用树套树。

点击查看代码
#include<bits/stdc++.h>
#pragma GCC optimize(2,3,"Ofast")
#define int unsigned int
#define inf 1e18
#define N 100005
#define mid ((l+r)>>1)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pii pair<int,int>
#define il inline
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
il int read(){
    int w=0,h=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')h=-h;ch=getchar();}
    while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
    return w*h;
}
int n,m,a[N];
namespace Treap{
	struct Data{int ls,rs,siz,cnt,val,prio;}tr[N<<2];int rt[N],tot;
	int Newnode(int val){tr[++tot]={0,0,1,1,val,rand()};return tot;}
	void Pushup(int k){tr[k].siz=tr[tr[k].ls].siz+tr[tr[k].rs].siz+tr[k].cnt;}
	void Zig(int&k){
		int p=tr[k].ls;
		tr[k].ls=tr[p].rs;
		tr[p].rs=k;
		k=p;
		Pushup(tr[k].rs);
		Pushup(k);
	}
	void Zag(int&k){
		int p=tr[k].rs;
		tr[k].rs=tr[p].ls;
		tr[p].ls=k;
		k=p;
		Pushup(tr[k].ls);
		Pushup(k);
	}
	void Insert(int&k,int val){
		if(!k)return void(k=Newnode(val));
		if(val==tr[k].val)tr[k].cnt++;
		if(val<tr[k].val){
			Insert(tr[k].ls,val);
			if(tr[tr[k].ls].prio>tr[k].prio)Zig(k);
		}
		if(val>tr[k].val){
			Insert(tr[k].rs,val);
			if(tr[tr[k].rs].prio>tr[k].prio)Zag(k);
		}
		Pushup(k);
	}
	void Delete(int&k,int val){
		if(!k)return;
		if(val==tr[k].val){
			if(tr[k].cnt>1)tr[k].cnt--;
			else if(tr[k].ls||tr[k].rs){
				if(!tr[k].rs||tr[tr[k].ls].prio>tr[tr[k].rs].prio)
					Zig(k),Delete(tr[k].rs,val);
				else Zag(k),Delete(tr[k].ls,val);
			}
			else k=0;
			Pushup(k);
			return;
		}
		if(val<tr[k].val)Delete(tr[k].ls,val);
		if(val>tr[k].val)Delete(tr[k].rs,val);
		Pushup(k);
	}
	int Pre(int k,int val){
		int res=-1;
		while(k){
			if(val>tr[k].val)res=tr[k].val,k=tr[k].rs;
			else k=tr[k].ls;
		}
		return res;
	}
	int Nxt(int k,int val){
		int res=-1;
		while(k){
			if(val<tr[k].val)res=tr[k].val,k=tr[k].ls;
			else k=tr[k].rs;
		}
		return res;
	}
}
using namespace Treap;
namespace SGT{
	struct Data{int Sum,ls,rs;}tr[N*180];int tot;
	void Modify(int&k,int l,int r,int x,int y,int t){
		if(!k)k=++tot;
		tr[k].Sum+=t*(y-x);
		if(l==r)return;
		if(x<=mid)Modify(tr[k].ls,l,mid,x,y,t);
		if(mid<x)Modify(tr[k].rs,mid+1,r,x,y,t);
	}
	int Query(int k,int l,int r,int x,int y){
		if(l>=x&&r<=y)return tr[k].Sum;
		if(y<=mid)return Query(tr[k].ls,l,mid,x,y);
		if(mid<x)return Query(tr[k].rs,mid+1,r,x,y);
		return Query(tr[k].ls,l,mid,x,y)+Query(tr[k].rs,mid+1,r,x,y);
	}
}
namespace Tree{
#define ls k<<1
#define rs k<<1|1
	int rt[N<<2];
	void Modify(int k,int l,int r,int x,int y,int t){
		SGT::Modify(rt[k],1,n,y,x,t);
		if(l==r)return;
		if(x<=mid)Modify(ls,l,mid,x,y,t);
		if(mid<x)Modify(rs,mid+1,r,x,y,t);
	}
	int Query(int k,int l,int r,int x,int y){
		if(l>=x&&r<=y)return SGT::Query(rt[k],1,n,x,y);
		if(y<=mid)return Query(ls,l,mid,x,y);
		if(mid<x)return Query(rs,mid+1,r,x,y);
		return Query(ls,l,mid,x,y)+Query(rs,mid+1,r,x,y);
	}
}
signed main(){
	n=read();m=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		int pre=Pre(rt[a[i]],i);
		Insert(rt[a[i]],i);
		if(~pre)Tree::Modify(1,1,n,i,pre,1);
	}
	while(m--){
		int opt=read(),x=read(),y=read(),pre,nxt;
		if(opt==1){
			Delete(rt[a[x]],x);
			pre=Pre(rt[a[x]],x);nxt=Nxt(rt[a[x]],x);
			if(~pre)Tree::Modify(1,1,n,x,pre,-1);
			if(~nxt){
				Tree::Modify(1,1,n,nxt,x,-1);
				if(~pre)Tree::Modify(1,1,n,nxt,pre,1);
			}
			a[x]=y;
			pre=Pre(rt[a[x]],x);nxt=Nxt(rt[a[x]],x);
			if(~nxt){
				if(~pre)Tree::Modify(1,1,n,nxt,pre,-1);
				Tree::Modify(1,1,n,nxt,x,1);
			}
			if(~pre)Tree::Modify(1,1,n,x,pre,1);
			Insert(rt[a[x]],x);
		}
		if(opt==2)printf("%lld\n",Tree::Query(1,1,n,x,y));
	}
    return 0;
}
posted @ 2022-07-04 20:31  pidan007  阅读(39)  评论(0编辑  收藏  举报