梦幻布丁——奇妙的线段树合并

description

\(n\) 个布丁摆成一行,进行 \(m\) 次操作。每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色。

solution

线段树合并板子,用到动态开点.复杂度看似高,由于答案单调不增,所以实际上均摊下来只有\(\Omicron(n\log n)\)的复杂度.代码贴这里方便复习吧.

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<ctime>
#define R register
#define next MabLcdG
#define mod 1
#define debug puts("mlg")
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writesp(ll x);
inline void writeln(ll x);
ll n,m;
const ll maxn=1e6;
struct Seg{
	ll lc,rc,lv,rv,dat;
}t[maxn<<2];
ll rt[maxn];
ll cnt;
inline void update(ll p){
	t[p].lv=t[p].lc?t[t[p].lc].lv:t[t[p].rc].lv;
	t[p].rv=t[p].rc?t[t[p].rc].rv:t[t[p].lc].lv;
	t[p].dat=t[t[p].lc].dat+t[t[p].rc].dat-(t[t[p].lc].rv+1==t[t[p].rc].lv);
}

inline void change(ll &p,ll l,ll r,ll x){
	if(!p) p=++cnt;
	if(l==r){t[p].lv=t[p].rv=x;t[p].dat=1;return;}
	ll mid=l+r>>1;
	if(x<=mid) change(t[p].lc,l,mid,x);
	else change(t[p].rc,mid+1,r,x);
	update(p);
}

inline void merge(ll &x,ll &y,ll l,ll r){
	if(!x||!y){x+=y;return;}
	if(l==r){t[x].lv=t[x].rv=l;t[x].dat=1;return;}
	ll mid=l+r>>1;
	merge(t[x].lc,t[y].lc,l,mid);
	merge(t[x].rc,t[y].rc,mid+1,r);
	update(x);
}
ll ans;
int main(){
	n=read();m=read();
	for(R ll i=1,x;i<=n;i++){
		x=read();
		ans-=t[rt[x]].dat;
		change(rt[x],1,n,i);
		ans+=t[rt[x]].dat;
	}
	while(m--){
		ll op=read();
		if(op==1){
			ll x=read(),y=read();
			if(x==y) continue;
			ans-=t[rt[x]].dat;
			ans-=t[rt[y]].dat;
			merge(rt[y],rt[x],1,n);
			rt[x]=0;
			ans+=t[rt[y]].dat;
		}
		else{
			writeln(ans);
		}
	}
} 
inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x);putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}
posted @ 2020-08-07 07:28  月落乌啼算钱  阅读(110)  评论(0编辑  收藏  举报