BZOJ 2049 动态树-模板题

2024-08-23 14:38
文章标签 动态 模板 bzoj 2049

本文主要是介绍BZOJ 2049 动态树-模板题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

BZOJ 2049:[Sdoi2008]Cave 洞穴勘测

 

辉辉有一台监测仪器可以实时将通道的每一次改变状况在辉辉手边的终端机上显示:如果监测到洞穴u和洞穴v之间出现了一条通道,终端机上会显示一条指令 Connect u v 。如果监测到洞穴u和洞穴v之间的通道被毁,终端机上会显示一条指令 Destroy u v 。经过长期的艰苦卓绝的手工推算,辉辉发现一个奇怪的现象:无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径。因而,辉辉坚信这是由于某种本质规律的支配导致的。因而,辉辉更加夜以继日地坚守在终端机之前,试图通过通道的改变情况来研究这条本质规律。然而,终于有一天,辉辉在堆积成山的演算纸中崩溃了……他把终端机往地面一砸(终端机也足够坚固无法破坏),转而求助于你,说道:“你老兄把这程序写写吧”。辉辉希望能随时通过终端机发出指令 Query u v,向监测仪询问此时洞穴u和洞穴v是否连通。现在你要为他编写程序回答每一次询问。已知在第一条指令显示之前,JSZX洞穴群中没有任何通道存在。

Input

第一行为两个正整数n(10000)和m(200000),分别表示洞穴的个数和终端机上出现过的指令的个数。以下m行,依次表示终端机上出现的各条指令。每行开头是一个表示指令种类的字符串s("Connect”、”Destroy”或者”Query”,区分大小写),之后有两个整数u和v (1≤u, v≤n且u≠v) 分别表示两个洞穴的编号。

Output

对每个Query指令,输出洞穴u和洞穴v是否互相连通:是输出”Yes”,否则输出”No”。(不含双引号)

Sample Input

Sample Output

200    5

Query      123  127

Connect     123  127

Query       123  127

Destroy     127  123

Query           123  127

3       5

Connect     1     2

Connect     3     1

Query       2     3

Destroy     1     3

Query           2   3

No

Yes

No

 

Yes

No

 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define N 10010
struct Node {Node *ch[2],*fa;int rev,value;Node(){ch[0] = ch[1] = fa = NULL;rev = 0;}Node(int v){ch[0] = ch[1] = fa = NULL;rev = 0; value = v;}int lr_ch(Node *(&node)) {this -> push_down();return ch[1] == node;}void link_ch(Node *(&node),int d) {ch[d] = node;if(node!=NULL) node -> fa = this;}void push_rev(Node *(&node)) {swap(node->ch[0],node->ch[1]);node->rev ^= 1;}void push_down() {if(rev == 0) return;if(ch[0] != NULL) push_rev(ch[0]);if(ch[1] != NULL) push_rev(ch[1]);rev = 0;}
}*root,*nod[N];
inline int is_Root(Node *(&node));// 一定要注意splay之前 小棵splay树上根node之间的节点下放
void push_Path(Node *(&node)){Node *stack[N],*now = node;int top = 0;
while(!is_Root(now)){ 
stack[++top] = now;now  =  now -> fa;
}    
stack[++top] = now;while(top != 0)   stack[top--] -> push_down();
}
//单旋操作,注意与splay模板的区别
void rotate(Node *(&node),int d) {Node *ff = node -> fa -> fa;Node *f = node -> fa;f -> link_ch(node->ch[d],d^1);//当ff为"天花板"时,"天花板"是没有孩子的if(!is_Root(f))    ff->link_ch(node,ff->lr_ch(f));else            node->fa = ff;node -> link_ch(f,d);
}
//注意splay的写法,别用函数递归,防止爆栈
void splay(Node *(&node)){push_Path(node);while(!is_Root(node)){node -> fa -> push_down();  node -> push_down();if(is_Root(node->fa)){rotate(node,node->fa->ch[0]==node);return;}int  b1 = (node->fa->fa->ch[0]==node->fa);int  b2 = (node->fa->ch[0]==node);if(b1==b2)   rotate(node->fa,b2);else         rotate(node,b2);rotate(node,b1);}
}
//判断node节点是否为一小棵splay树的根
inline int is_Root(Node *(&node)) {if(node->fa->ch[0]==node) return 0;if(node->fa->ch[1]==node) return 0;return 1;
}
//access操作,打通node节点与"天花板"root
void access(Node *(&node)) {Node *up = node,*down = NULL;while(up != root) {splay(up);up -> push_down();up -> ch[1] = down;down = up;  up = up -> fa;}
}
//将大森林的树根换成node!
void re_Root(Node *(&node)) {access(node);splay(node);node -> push_rev(node);
}
//要记住: link操作的前提是link后 不能形成环
void link(Node *(&node1),Node *(&node2)) {re_Root(node1);node1 -> fa = node2;access(node1);
}
//要记住: cut操作node1必须与node2有边存在
void cut(Node *(&node1),Node *(&node2)) {re_Root(node2);access(node1);splay(node1);node2 -> fa = root;node1 -> push_down();node1 -> ch[0] = NULL;
}
//判断node1余node2是否在同一棵小splay树中
int judge(Node *node1,Node *node2){while(node1->fa!=root) node1 = node1 -> fa;while(node2->fa!=root) node2 = node2 -> fa;return node1==node2;
}
//初始化所有节点与"天花板"
void init(int n) {root = new Node(-1);for(int i=1;i<=n;i++) {nod[i] = NULL;nod[i] = new Node(i);nod[i] -> fa = root;}
}
//释放节点所占空间;但是注意nod[i]节点没有被初始化
void delet(Node *(&node)){if(node==NULL) return;delet(node->ch[0]);delet(node->ch[1]);delete node;  node = NULL;
}
int main() {int n,m,x,y;char s[25];while(~scanf("%d%d",&n,&m)){init(n);for(int i = 1;i<=m;i++){scanf("%s%d%d",s,&x,&y);if(s[0]=='C') link(nod[x],nod[y]);if(s[0]=='D') cut(nod[x],nod[y]);if(s[0]=='Q') printf("%s\n",judge(nod[x],nod[y])?"Yes":"No");}delet(root);}return 0;
}


这篇关于BZOJ 2049 动态树-模板题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1099667

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

最大流、 最小费用最大流终极版模板

最大流  const int inf = 1000000000 ;const int maxn = 20000 , maxm = 500000 ;struct Edge{int v , f ,next ;Edge(){}Edge(int _v , int _f , int _next):v(_v) ,f(_f),next(_next){}};int sourse , mee

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d