• BZOJ.4530.[BJOI2014]大融合(LCT)


    题目链接 BZOJ
    洛谷

    详见这

    很明显题目是要求去掉一条边后两边子树sz[]的乘积。
    LCT维护的是链的信息,那么子树呢?
    我们用s_i[x]来记录轻边连向x的子树的和(记作虚儿子),那么sum[x]更新时就是sum[lson]+sum[rson]+val[x]+s_i[x]。
    现在需要s_i[x],考虑什么时候会影响它。
    Splay()影响的只是节点在辅助树Splay中的相对位置,并不会对树中的信息产生影响。
    Access()需要更改右儿子,即加上一个虚儿子加上一个实儿子,对应更新即可,如果只需要维护sum之类不需要Update()(一加一减)。
    Make_root()无影响。虽然使整棵树形态都发生了变化,但这一操作并不直接用来获取信息。
    Split()不需要考虑(仅是调用函数)。
    Find_root()无影响。
    Link()后y多了一个虚儿子,那么sum[y],s_i[y]加上x。这一步之前要将y旋到根(Access(y),Splay(y)),否则y以上的部分不会更新。
    Cut()无影响。虽然少了个儿子,但这一操作不会用来直接获取信息,下次获取信息时会更新,不会影响正确性。
    这样答案就是x,y两边s_i+1的乘积(分离出路径后实的就是x->y了,再加上自己),或是(y为根时)sz[x]*(sz[y]-sz[x])

    //3264kb	1380ms
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    const int N=1e5+5;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    namespace LCT
    {
    	#define lson son[x][0]
    	#define rson son[x][1]
    
    	int fa[N],son[N][2],sz[N],sz_i[N],sk[N];
    	bool tag[N];
    	inline void Update(int x){
    		sz[x]=sz[lson]+sz[rson]+1+sz_i[x];
    	}
    	inline bool n_root(int x){
    		return son[fa[x]][0]==x||son[fa[x]][1]==x;
    	}
    	inline void Rev(int x){
    		std::swap(lson,rson), tag[x]^=1;
    	}
    	inline void PushDown(int x){
    		if(tag[x]) Rev(lson),Rev(rson),tag[x]=0;
    	}
    	void Rotate(int x)
    	{
    		int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
    		if(n_root(a)) son[b][son[b][1]==a]=x;
    		if(son[x][r]) fa[son[x][r]]=a;
    		fa[a]=x, fa[x]=b, son[a][l]=son[x][r], son[x][r]=a;
    		Update(a);
    	}
    	void Splay(int x)
    	{
    		int t=1,a=x,b; sk[1]=x;//
    		while(n_root(a)) sk[++t]=a=fa[a];
    		while(t) PushDown(sk[t--]);
    		while(n_root(x))
    		{
    			a=fa[x], b=fa[a];
    			if(n_root(a)) Rotate(son[a][1]==x^son[b][1]==a?x:a);
    			Rotate(x);
    		}
    		Update(x);
    	}
    	void Access(int x){
    		for(int pre=0; x; x=fa[pre=x])
    		{
    			Splay(x);
    			sz_i[x]+=sz[rson], sz_i[x]-=sz[rson=pre];
    //			Update(x);
    		}
    	}
    	void Make_root(int x){
    		Access(x), Splay(x), Rev(x);
    	}
    	void Split(int x,int  y){
    		Make_root(x), Access(y), Splay(y);
    	}
    	void Link(int x,int y){
    		Split(x,y), sz_i[fa[x]=y]+=sz[x], Update(y);//更新!
    	}
    	long long Query(int x,int y){
    		Split(x,y); return 1ll*(sz_i[x]+1)*(sz_i[y]+1);//1ll*sz[x]*(sz[y]-sz[x]);
    	}
    }
    
    int main()
    {
    	int n=read(),q=read(),x,y; char opt[3];
    	for(int i=1; i<=n; ++i) LCT::sz[i]=1;
    	while(q--)
    	{
    		scanf("%s",opt),x=read(),y=read();
    		if(opt[0]=='A') LCT::Link(x,y);
    		else printf("%lld
    ",LCT::Query(x,y));
    	}
    	return 0;
    }
    
  • 相关阅读:
    DIY树莓派之随身工具箱
    经验分享 | Burpsuite抓取非HTTP流量
    版本控制工具:SVN和Maven的区别
    Dicom Conformance
    从Script到Code Blocks、Code Behind到MVC、MVP、MVVM
    MVC,MVP 和 MVVM 的图示
    DB2 触发器的写法及表主键结构的修改
    数据表增加列的时候赋默认值
    Mysql数据库乱码总结
    又在字符集上浪费时间
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8626617.html
走看看 - 开发者的网上家园