zoukankan      html  css  js  c++  java
  • CF1556G Gates to Another World

    一、题目

    点此看题

    二、解法

    考虑本题数据范围极大并且删除操作是以区间的形式给出的,那么可以考虑动态开点线段树

    继续考虑如果我们用线段树做有什么性质,其实就是把左儿子和右儿子的叶子节点对应连边,简而言之,我们把它转化成了一个对应点优化连边问题

    你可能会联想到萌萌哒那道题,所以我们不在线维护连通块,而在读入所有询问修改之后做优化连边。具体来说我们把每个点打上一个删除标记 (t_i),表示删除这个点的时间,如果违背删除那么 (t_i=m+1)

    那么最后应该如何连边呢?考虑一个"叶节点"(并不是真正的叶子,而是动态开点之后没有儿子的结点)中所有叶节点的行为平行,因为它们删除的时间相同,并且一定联通,所有可以把他们当成一个点来考虑。

    加入上述优化之后复杂度就正确了,也就是对于每个非叶节点一直递归下去,直到找到两个叶子连边,这条边被删除的时间是 (min(t_x,t_y)),求出所有边之后我们离线逆序加边,用并查集判断连通性即可。

    因为每个叶子只会在 (n) 个祖先处有 (1) 的贡献,所以总时间复杂度 (O(n^2m)),空间复杂度也是 (O(n^2m)),要注意卡空间。

    三、总结

    优化对应点连边的方法是用数据结构维护某个量,读入所有修改后再优化建图。

    较大数据范围的解决方案:寻找等价类(本题的等价类就是"叶节点")

    //But now I walk the line on the higher ground
    //my pride in the clouds
    #include <cstdio>
    #include <vector>
    #include <iostream>
    using namespace std;
    const int M = 50005;
    const int N = 100*M;
    #define Int long long
    #define pii pair<int,int>
    #define mp make_pair
    Int read()
    {
    	Int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    Int n,m,k,rt,cnt,ls[N],rs[N],rm[N],a[M],b[M],fa[N];
    vector<pii> e[M];Int ans[M],pd[M];
    void down(Int x)
    {
    	if(!rm[x]) return ;
    	if(!ls[x]) ls[x]=++cnt;
    	if(!rs[x]) rs[x]=++cnt;
    	rm[ls[x]]=rm[rs[x]]=rm[x];rm[x]=0;
    }
    void ins(Int &x,Int l,Int r,Int L,Int R,Int c)
    {
    	if(!x) x=++cnt;
    	if(L>r || l>R) return ;
    	if(L<=l && r<=R)
    	{
    		rm[x]=c;
    		return ;
    	}
    	Int mid=(l+r)>>1;down(x);
    	ins(ls[x],l,mid,L,R,c);
    	ins(rs[x],mid+1,r,L,R,c);
    }
    Int leaf(Int x) {return !ls[x] && !rs[x];}
    Int loc(Int x,Int l,Int r,Int id)
    {
    	if(leaf(x)) return x;
    	Int mid=(l+r)>>1;
    	if(mid>=id) return loc(ls[x],l,mid,id);
    	return loc(rs[x],mid+1,r,id);
    }
    Int find(Int x)
    {
    	if(fa[x]!=x) fa[x]=find(fa[x]);
    	return fa[x];
    }
    void fuck(Int x,Int y)
    {
    	if(leaf(x) && leaf(y))
    	{
    		e[min(rm[x],rm[y])].push_back(mp(x,y));
    		return ;
    	}
    	if(leaf(x))
    	{
    		fuck(x,ls[y]);fuck(x,rs[y]);
    		return ;
    	}
    	if(leaf(y))
    	{
    		fuck(ls[x],y);fuck(rs[x],y);
    		return ;
    	}
    	fuck(ls[x],ls[y]);
    	fuck(rs[x],rs[y]);
    }
    signed main()
    {
    	n=read();m=read();k=(1ll<<n)-1;
    	rm[rt=cnt=1]=m+1;
    	for(Int i=1;i<=m;i++)
    	{
    		string s;cin>>s;
    		Int l=read(),r=read();
    		if(s[0]=='a') a[i]=l,b[i]=r,pd[i]=1;
    		else ins(rt,0,k,l,r,i);
    	}
    	for(Int i=1;i<=cnt;i++)
    		fa[i]=i;
    	for(Int i=1;i<=cnt;i++)
    		if(!leaf(i)) fuck(ls[i],rs[i]);
    	for(auto x:e[m+1])
    		fa[find(x.first)]=find(x.second);
    	for(Int i=m;i>=1;i--)
    	{
    		for(auto x:e[i])
    			fa[find(x.first)]=find(x.second);
    		ans[i]=find(loc(rt,0,k,a[i]))
    		==find(loc(rt,0,k,b[i]));
    	}
    	for(Int i=1;i<=m;i++)
    		if(pd[i]) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    一个空类会生成哪些默认函数
    What is VMR(Video Mixing Render)From MSDN
    DirectX backface culling(背面剔除)
    D3DPOOL(资源池)
    两道概率题供大家周末把玩
    空间两点间的距离
    n != n, n == n
    C++默认参数
    D3DPT_TRIANGLELIST与D3DPT_TRIANGLESTRIP
    D3D中的设备丢失
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15357002.html
Copyright © 2011-2022 走看看