zoukankan      html  css  js  c++  java
  • [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并)

    [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并)

    题面

    N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.

    (n,mleq 1 imes 10^5),颜色编号 (leq 1 imes 10^6)

    分析

    先考虑询问,我们可以对每种颜色分别求出这种颜色的连续段有多少个。可以用权值线段树实现。第c棵权值线段树维护颜色c的位置出现情况,如果第i个位置颜色为c.则线段树上[i,i]为1。

    这样我们就只要维护一下区间连续段个数就可以了。每个区间维护3个值:lv,rv,sum,分别表示左端点是否为1,右端点是否为1和总段数,合并两个区间的时候如果如果左区间的右端点和右区间的左端点为1,那么两段可以拼成一段连续的,答案为两个区间的段数之和-1,否则 答案为两个区间的段数之和。

    把所有颜色的线段树的答案(根节点sum值)加起来,就是初始的颜色段数。

    然后考虑修改。如果我们把颜色x变成颜色y,相当于把x对应的线段树合并到y对应的线段树上,然后删除线段树x。合并就是模板的线段树合并,复杂度(O(log n)),而删除只需要把x对应的线段树的根设成0即可,复杂度是(O(1))的。每次都求一遍答案显然会超时,我们只需要考虑一次修改操作对答案的变化量。我们先减去线段树x,y的答案,合并后再加上线段树y的答案即可

    总时间复杂度(O(m log n))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring> 
    #define maxn 100000
    #define maxlogc 25
    #define maxc 1000000 
    using namespace std;
    int n,m;
    int a[maxn+5];
    
    struct segment_tree{
    //每棵线段树维护一种颜色c的位置出现情况,如果第i个位置颜色为c.则线段树上[i,i]为1 
    #define lson(x) tree[x].ls
    #define rson(x) tree[x].rs
    	struct node{
    		int	ls;
    		int rs;
    		int lv;//区间左端点是否为1 
    		int rv;//区间右端点是否为1 
    		int sum;//总段数 
    	}tree[maxn*maxlogc+5];
    	int ptr;
    	void push_up(int x){
    		tree[x].lv=tree[lson(x)].lv;
    		tree[x].rv=tree[rson(x)].rv;
    		tree[x].sum=tree[lson(x)].sum+tree[rson(x)].sum-(tree[lson(x)].rv==1&&tree[rson(x)].lv==1);
    		//如果左区间的右侧和右区间的左侧为1,那么两段可以拼成一段连续的,答案-1 
    	}
    	void update(int &x,int upos,int l,int r){
    		if(!x) x=++ptr;
    		if(l==r){
    			tree[x].lv=tree[x].rv=tree[x].sum=1;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(upos<=mid) update(tree[x].ls,upos,l,mid);
    		else update(tree[x].rs,upos,mid+1,r);
    		push_up(x);
    	}
    	int merge(int x,int y,int l,int r){
    		if(!x||!y) return x+y;
    		if(l==r){
    			tree[x].sum|=tree[y].sum;
    			tree[x].lv|=tree[y].lv;
    			tree[x].rv|=tree[y].rv;
    			return x;
    		} 
    		int mid=(l+r)>>1;
    		tree[x].ls=merge(tree[x].ls,tree[y].ls,l,mid);
    		tree[x].rs=merge(tree[x].rs,tree[y].rs,mid+1,r);
    		push_up(x);
    		return x;
    	}
    }T;
    int root[maxc+5];
    int main(){
    	int cmd,x,y;
    	scanf("%d %d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		T.update(root[a[i]],i,1,n);
    	}
    	int ans=0;
    	for(int i=1;i<=maxc;i++) ans+=T.tree[root[i]].sum;
    	for(int i=1;i<=m;i++){
    		scanf("%d",&cmd);
    		if(cmd==1){
    			scanf("%d %d",&x,&y);
    			if(x==y) continue;
    			ans-=T.tree[root[x]].sum;
    			ans-=T.tree[root[y]].sum;
    			root[y]=T.merge(root[y],root[x],1,n);//一定要写root[y]= 
    			ans+=T.tree[root[y]].sum;
    			root[x]=0; //记得删除x这棵树 
    		}
    		else printf("%d
    ",ans);
    	}
    }
    
  • 相关阅读:
    HDU 2955 Robberies
    HDU 2546 饭卡
    poj 3628 Bookshelf 2
    poj 3624 Charm Bracelet
    celery -1
    ☀【Grunt】插件
    【MooTools】
    【Grunt】
    ↗☻【PHP与MySQL程序设计 #BOOK#】第3章 PHP基础
    【CSS】
  • 原文地址:https://www.cnblogs.com/birchtree/p/11314563.html
Copyright © 2011-2022 走看看