• 【题解】梦幻布丁


    (Question)

    题目大意:给一个颜色序列,待修改,求区间颜色段数。

    (Solution)

    考虑线段树合并。

    对于每一个颜色建一个线段树,维护每个颜色出现的位置。同时维护区间的颜色段数,以及最左端、最右端的颜色位置。

    于是,对于合并颜色(x,y).,·将它们对应线段树合并即可。合并时,当一树为空时,直接返回;当递归到叶子时,左右均为该处(pos).颜色段为1,返回即可。

    对于插入时,与合并处理边界一样。

    维护信息时,左端信息优先考虑左子树,右端信息优先考虑右子树,总信息将左右颜色段相加,但若两端相交处颜色相同,则需要-1.

    修改时一同维护(ans.)即可。

    (蒟蒻第一次写非权值线段树的线段树合并)

    ( ext{Code:})

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int MAXN=1e6+10;
    int n,m,ans;
    int rt[MAXN],ch[MAXN<<5][2],rub[MAXN<<5],tot,cnt;
    int a[MAXN],ls[MAXN<<5],rs[MAXN<<5],ms[MAXN<<5];
    inline int build(){return (cnt?rub[cnt--]:++tot);}
    inline void del(int x){
    	ch[x][0]=ch[x][1]=0;
    	ls[x]=rs[x]=ms[x]=0;
    	rub[++cnt]=x;return;
    }
    inline void pushup(int x){
    	ls[x]=ls[ch[x][0]]?ls[ch[x][0]]:ls[ch[x][1]];
    	rs[x]=rs[ch[x][1]]?rs[ch[x][1]]:rs[ch[x][0]];
    	ms[x]=ms[ch[x][0]]+ms[ch[x][1]]-(rs[ch[x][0]]+1==ls[ch[x][1]]);
    }
    void modify(int &p,int l,int r,int pos){
    	if(!p)p=build();
    	if(l==r){
    		ls[p]=rs[p]=pos,ms[p]=1;
    		return;
    	}
    	int mid=l+r>>1;
    	if(pos<=mid)modify(ch[p][0],l,mid,pos);
    	else modify(ch[p][1],mid+1,r,pos);
    	pushup(p);
    }
    int merge(int x,int y,int l,int r){
    	if(!x||!y){return x+y;}
    	if(l==r){
    		ls[x]=rs[x]=l;ms[x]=1;
    		del(y);return x;
    	}
    	int mid=l+r>>1;
    	ch[x][0]=merge(ch[x][0],ch[y][0],l,mid);
    	ch[x][1]=merge(ch[x][1],ch[y][1],mid+1,r);
    	del(y);pushup(x);return x;
    }
    inline void solve(){printf("%lld
    ",ans);}
    void change(int x,int y){
    	ans-=ms[rt[x]];ans-=ms[rt[y]]; 
    	rt[y]=merge(rt[y],rt[x],1,n);
    	ans+=ms[rt[y]];rt[x]=0;
    }
    signed main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    	for(int i=1;i<=n;++i){
    		ans-=ms[rt[a[i]]];
    		modify(rt[a[i]],1,n,i);
    		ans+=ms[rt[a[i]]];
    	}
    	int Q=m;
    	for(;Q;Q--){
    		int opt;
    		scanf("%lld",&opt);
    		if(opt==2)solve();
    		else {
    			int x,y;
    			scanf("%lld%lld",&x,&y);
    			if(x==y)continue;
    			change(x,y);
    		}
    	}
    	return 0;
    } 
    
  • 相关阅读:
    UnxUtils让windows下的dos命令变为linux下的命令
    Python多线程&进程
    Web前端工程师-优秀简历汇总
    最详细的Vuex教程
    Vue2.0 探索之路——生命周期和钩子函数的一些理解
    理解 $nextTick 的作用
    使用git rebase合并多次commit
    vim 退出命令(保存、放弃保存)
    Vue获取DOM元素样式 && 样式更改
    Vue Router的配置
  • 原文地址:https://www.cnblogs.com/h-lka/p/12587136.html
Copyright © 2020-2023  润新知