• 洛谷P4219 lct维护子树信息


    题意:

    给出 n n n个独立的点,处理以下 q q q个操作,每个操作只会是如下操作之一

    (1)连接 x , y x,y x,y,保证原本没有边存在

    (2)查询边 ( x , y ) (x,y) (x,y)的负荷,定义负荷为树上经过 ( x , y ) (x,y) (x,y)的简单路径的个数

    L C T LCT LCT维护(原树中)子树信息

    s i z e size size是当前结点为根的情况下的子树信息和, v s i z e ( v i r t u a l _ s i z e ) vsize(virtual\_size) vsize(virtual_size)是当前结点为根的情况下的所有虚儿子的子树和。

    如果给定根,即已知 x x x的父节点 f a fa fa,那么只需要 s p l i t ( x , f a ) split(x,fa) split(x,fa) x x x v s i z e vsize vsize就已经是原树的子树信息和了。

    更一般的, s i z e size size维护的是原树这个图的连接的所有连通分量的信息和,如果给定根要找出子树信息和,只需要剥离他的父亲即可。

    另外,在维护子树信息时, l i n k ( x , y ) link(x,y) link(x,y)时,最好先 s p l a y ( y ) splay(y) splay(y)。因为 y y y也有父亲,给 y y y连接了虚儿子后,也需要 p u s h _ u p   y push\_up\ y push_up y的父亲,先 s p l a y ( y ) splay(y) splay(y)后, y y y就没有父亲了,也就不需要更新。

    也可以在连接虚儿子后 s p l a y ( y ) splay(y) splay(y),此时的含义就是手动更新 y y y的祖先们。

    维护子树信息只需要在更改了虚实关系的函数更新 v s i z e vsize vsize即可,仅需在 l i n k , a c c e s s link,access link,access中更新

    #include
    #define ll long long
    using namespace std;
    
    struct LCT
    {
    	struct node
    	{
    		int v,tag,son[2],fa,size,vsize;
    	};
    	stack<int>s;
    	vector<node>tree;
    	LCT():tree(100005){}
    	bool isroot(int x)
    	{
    		return tree[tree[x].fa].son[0]!=x&&tree[tree[x].fa].son[1]!=x;
    	}
    	int getson(int x,int y)
    	{
    		return x==tree[y].son[1];
    	}
    	void push_up(int x)
    	{
    		tree[x].size=1+tree[x].vsize+tree[tree[x].son[0]].size+tree[tree[x].son[1]].size;
    	}
    	void rotate(int x)
    	{
    		int y=tree[x].fa,z=tree[y].fa;
    		int k1=getson(x,y),k2=getson(y,z);
    		tree[x].fa=z;
    		if(!isroot(y)) tree[z].son[k2]=x;
    		tree[y].son[k1]=tree[x].son[!k1];
    		if(tree[x].son[!k1]) tree[tree[x].son[!k1]].fa=y;
    		tree[x].son[!k1]=y;
    		tree[y].fa=x;
    		push_up(y); push_up(x);
    	}
    	void reverse(int x)
    	{
    		swap(tree[x].son[0],tree[x].son[1]);
    		tree[x].tag^=1;
    	}
    	void push_down(int x)
    	{
    		if(!tree[x].tag) return;
    		for(int i=0;i<=1;i++)
    			if(tree[x].son[i]) reverse(tree[x].son[i]);
    		tree[x].tag=0;
    	}
    	void splay(int x)
    	{
    		int now=x;
            push_up(now);
    		s.push(now);
    		while(!isroot(now))
    		{
    			s.push(tree[now].fa);
                // push_up(tree[now].fa);
    			now=tree[now].fa;
    		}
    		while(!s.empty())
    		{
    			push_down(s.top());
    			s.pop();
    		}
    		while(!isroot(x))
    		{
    			int y=tree[x].fa,z=tree[y].fa;
    			int k1=getson(x,y),k2=getson(y,z);
    			if(!isroot(y))
    			{
    				if(k1==k2) rotate(y);
    				else rotate(x);
    			}
    			rotate(x);
    		}
    	}
    	void access(int x)//打通root->x的splay
    	{
    		int last=0;
    		while(x)
    		{
    			splay(x);
                tree[x].vsize+=tree[tree[x].son[1]].size-tree[last].size;
    			tree[x].son[1]=last;
    			push_up(last=x);
    			x=tree[x].fa;
    		}
    	}
    	void makeroot(int x)
    	{
    		access(x);
    		splay(x);
    		reverse(x);
    	}
    	int findroot(int x)
    	{
    		access(x);
    		splay(x);
    		while(tree[x].son[0])
    		{
    			push_down(x);
    			x=tree[x].son[0];
    		}
    		splay(x);
    		return x;
    	}
    	void split(int x,int y)
    	{
    		makeroot(x);
    		access(y);
    		splay(y);
    	}
    	void link(int x,int y)
    	{
    		makeroot(x);
    		if(x==findroot(y)) return;
            splay(y);
    		tree[x].fa=y;
            tree[y].vsize+=tree[x].size;
            push_up(y);
    	}
    	// void cut(int x,int y)
    	// {
    	// 	makeroot(x);
    	// 	if(findroot(y)!=x||tree[y].fa!=x||tree[y].son[0]) return;
    	// 	tree[y].fa=tree[x].son[1]=0;
    	// }
    }lct;
    
    int n,q;
    
    int main()
    {
        scanf("%d%d",&n,&q);
        while(q--)
        {
            char s[5]; int x,y;
            scanf("%s%d%d",s+1,&x,&y);
            if(s[1]=='A') lct.link(x,y);
            else
            {
                lct.split(x,y);
                printf("%lld\n",1ll*(lct.tree[x].vsize+1)*(lct.tree[y].vsize+1));
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
  • 相关阅读:
    不同岛屿的数量
    基于Python实现的一款轻量、强大、好用的视频处理软件,可缩视频、转码视频、倒放视频、合并片段、根据字幕裁切片段、自动配字幕等
    JavaWeb传统商城(MVC三层架构)的促销功能模块【进阶版】
    2023华为杯数学建模研赛A题B题C题D题E题F题思路代码成品分享
    【车道线检测】霍夫变换(HoughLines)检测直线详解
    PAT乙级【Java题解合集】
    农村文化产业概论作业一(第一章~第二章)
    MySQL中的索引事务(1)索引----》数据库运行的原理知识+面试题~
    uniapp快速入门系列(2)- Vue基础知识
    27.阻塞队列
  • 原文地址:https://blog.csdn.net/stdforces/article/details/126706651