zoukankan      html  css  js  c++  java
  • [Ynoi2016]镜中的昆虫

    题目大意:

    给定一个序列,有2个操作:

    1. 区间覆盖。
    2. 区间数颜色。

    解题思路:

    珂朵莉树+树套树。

    看到区间覆盖当然想到珂朵莉树然而这是Ynoi

    所以我们得优化掉珂朵莉树那个暴力过程。

    考虑对每个位置,记录它这个颜色前一次出现的位置pre(它本身是第一次则为0)。

    对一段颜色相同的区间,除了第一个位置,其他位置的pre都是位置-1。

    用树套树,第一维为原本位置,第二维为pre,然后对于查询$[l,r]$区间的颜色个数,相当于$[l,r]$区间,pre在$[0,l-1]$的个数。

    考虑一次修改,最多增加$O(m)$个区间,所以总区间个数是$O(n+m)$的。所以暴力删除复杂度是对的。

    用珂朵莉树(其实是个set,不过珂朵莉树的split比较方便)维护相同颜色区间,对每种颜色再开set存所有区间。

    然后对于每次修改,先把pre可能变动的位置弄出来,再修改珂朵莉树和set里的信息,最后再重新求那些pre,在树套树上修改即可。

    时间复杂度$O((n+m)log^2 n)$。

    C++ Code:

    #include<cstdio>
    #include<cctype>
    #include<set>
    #include<map>
    const int N=100005,M=1.5e7+5;
    struct istream{
    	char buf[23333333],*s;
    	inline istream(){
    		buf[fread(s=buf,1,23333330,stdin)]='
    ';fclose(stdin);
    	}
    	inline istream&operator>>(int&d){
    		for(d=0;!isdigit(*s);++s);
    		while(isdigit(*s))d=(d<<3)+(d<<1)+(*s++^'0');
    		return*this;
    	}
    }cin;
    struct ostream{
    	char buf[12000005],*s;
    	inline ostream(){s=buf;}
    	inline ostream&operator<<(int d){
    		if(!d)*s++='0';else{
    			static int w;
    			for(w=1;w<=d;w*=10);for(;w/=10;d%=w)*s++=d/w^'0';
    		}
    		return*this;
    	}
    	inline ostream&operator<<(const char&c){*s++=c;return*this;}
    	inline void flush(){fwrite(buf,1,s-buf,stdout);s=buf;}
    	inline~ostream(){flush();}
    }cout;
    struct node{
    	int l,r;mutable int col;
    	inline bool operator<(const node&r)const{return l<r.l;}
    };
    std::set<node>s;
    typedef std::set<node>::iterator iter;
    std::set<std::pair<int,int> >cl[N<<1];
    std::map<int,int>ys;int tot=0,nodes=0;
    int n,m,pp[N],rt[N],pw[N];
    int ls[M],rs[M],sz[M];
    iter split(int pos){
        iter it=s.lower_bound((node){pos});
        if(it!=s.end()&&it->l==pos)return it;
        --it;
        const int l=it->l,r=it->r,val=it->col;
        s.erase(it);
        cl[val].erase(std::make_pair(l,r));
        s.insert((node){l,pos-1,val});
        cl[val].insert(std::make_pair(l,pos-1));
        cl[val].insert(std::make_pair(pos,r));
        return s.insert((node){pos,r,val}).first;
    }
    void modify2D(int&o,int l,int r,const int&pos,const int&dlt){
    	if(!o)o=++nodes;
    	sz[o]+=dlt;
    	if(l==r)return;
    	const int mid=l+r>>1;
    	if(pos<=mid)modify2D(ls[o],l,mid,pos,dlt);else modify2D(rs[o],mid+1,r,pos,dlt);
    }
    void modify1D(int i,int pre,int f){for(;i<=n;i+=i&-i)modify2D(rt[i],0,n,pre,f);}
    int query2D(int o,int l,int r,const int&L,const int&R){
    	if(!o)return 0;
    	if(L<=l&&r<=R)return sz[o];
    	const int mid=l+r>>1;
    	if(L<=mid&&mid<R)return query2D(ls[o],l,mid,L,R)+query2D(rs[o],mid+1,r,L,R);
    	if(L<=mid)return query2D(ls[o],l,mid,L,R);return query2D(rs[o],mid+1,r,L,R);
    }
    int query1D(int l,int r){
    	int ret=0;
    	for(int i=r;i;i^=i&-i)ret+=query2D(rt[i],0,n,0,l-1);
    	for(int i=l-1;i;i^=i&-i)ret-=query2D(rt[i],0,n,0,l-1);
    	return ret;
    }
    int main(){
    	cin>>n>>m;
    	int preL=1,pre;cin>>pre;
    	for(int i=2;i<=n;++i){
    		int now;
    		cin>>now;
    		if(now!=pre)s.insert((node){preL,i-1,pre}),preL=i,pre=now;
    	}
    	s.insert((node){preL,n,pre});
    	s.insert((node){n+1});
    	for(int i=1;i<=n+m;++i)cl[i].insert(std::make_pair(0,0));
    	for(iter i=s.begin();i!=s.end();++i){
    		if(i->l>n)break;
    		if(!ys.count(i->col))ys[i->col]=++tot;
    		i->col=ys[i->col];
    		cl[i->col].insert(std::make_pair(i->l,i->r));
    		for(int j=i->l+1;j<=i->r;++j)modify1D(j,j-1,1),pw[j]=j-1;
    		modify1D(i->l,pp[i->col],1);pw[i->l]=pp[i->col];
    		pp[i->col]=i->r;
    	}
    	while(m--){
    		int op,l,r;
    		cin>>op>>l>>r;
    		if(op==1){
    			static std::set<int>trans;
    			trans.clear();
    			int x;cin>>x;if(!ys.count(x))ys[x]=++tot;x=ys[x];
    			iter R=split(r+1),L=split(l);
    			for(iter i=L;i!=R;++i){
    				trans.insert(i->l);
    				auto it=cl[i->col].upper_bound(std::make_pair(i->l,i->r));
    				if(it!=cl[i->col].end())trans.insert(it->first);
    				cl[i->col].erase(std::make_pair(i->l,i->r));
    			}
    			s.erase(L,R);
    			s.insert((node){l,r,x});
    			cl[x].insert(std::make_pair(l,r));
    			const auto it=(cl[x].upper_bound(std::make_pair(l,r)));
    			if(it!=cl[x].end())trans.insert(it->first);
    			for(int it:trans){
    				iter info=--s.upper_bound((node){it});
    				modify1D(it,pw[it],-1);
    				if(it==info->l)pw[it]=(--cl[info->col].lower_bound(std::make_pair(info->l,info->r)))->second;else
    				pw[it]=it-1;
    				modify1D(it,pw[it],1);
    			}
    		}else cout<<query1D(l,r)<<'
    ';
    	}
    	return 0;
    }
  • 相关阅读:
    LeetCode分类专题(五)——动态规划1-子序列
    LeetCode分类专题(四)——双指针和滑动窗口1
    LeetCode分类专题(三)——二分查找1
    消息队列(一)——Kafka概述
    Java多线程(五)——synchronized关键字原理
    Java多线程(四)——volatile关键字原理
    Redis(五)——主从复制、哨兵
    Redis(四)——过期、持久化、事件
    Redis(三)——底层数据结构
    MySQL知识点
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/10361048.html
Copyright © 2011-2022 走看看