【BZOJ3673】【可持久化并查集】可持久化并查集 by zky

Description

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

0<n,m<=2*10^4

Input

Output

Sample Input

5 6
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2

Sample Output

1
0
1

HINT

Source

出题人大S

【分析】

出题人给我滚出来!保证不打死你!

真是***了,你题意描述清楚点会死啊。。调了将近2个小时...结果是题目理解错了....尼玛返回也算作操作啊。

思路还是蛮简单的。

用主席树维护一下并查集的fa数组就行了。

按照这种说法树状数组也应该可以可持久化了

  1 /*
  2 唐代李商隐
  3 《无题·昨夜星辰昨夜风》
  4
  5 昨夜星辰昨夜风,画楼西畔桂堂东。
  6 身无彩凤双飞翼,心有灵犀一点通。
  7 隔座送钩春酒暖,分曹射覆蜡灯红。
  8 嗟余听鼓应官去,走马兰台类转蓬。
  9 */
 10 #include <iostream>
 11 #include <cstdio>
 12 #include <algorithm>
 13 #include <cstring>
 14 #include <vector>
 15 #include <utility>
 16 #include <iomanip>
 17 #include <string>
 18 #include <cmath>
 19 #include <queue>
 20 #include <assert.h>
 21 #include <map>
 22 #include <ctime>
 23 #include <cstdlib>
 24 #include <stack>
 25 #define LOCAL
 26 const int MAXN = 20000 * 10 * 20 + 10;
 27 //const int MAXM = 20000 + 10;
 28 const int INF = 100000000;
 29 const int SIZE = 450;
 30 const int maxnode =  0x7fffffff + 10;
 31 using namespace std;
 32 int n, m;//n为元素总个数
 33 struct SEGTREE{
 34        //路径压缩+启发式合并还要用主席树OAO
 35        struct Node{
 36               Node *ch[2];
 37               int l, r;
 38               int num;//其实除了叶子节点其他都是打酱油的,num是该节点的fa值
 39        }mem[MAXN], *root[200000 * 10 + 10];
 40        int tot;
 41
 42        void init(){
 43             tot = 0;
 44             root[0] = NULL;
 45             for (int i = 1; i <= 200000 * 10; i++) root[i] = NULL;
 46             build(root[0], 1, n);
 47             //printf("%d %d\n", root[0]->ch[0]->l, root[0]->ch[0]->r);
 48        }
 49        Node *NEW(int l, int r){
 50             Node *p = &mem[tot++];
 51             p->l = l;
 52             p->r = r;
 53             p->num = -1;
 54             p->ch[0] = p->ch[1] = NULL;
 55             return p;
 56        }
 57        void build(Node *&t, int l, int r){
 58             if (t == NULL){
 59                   t = NEW(l, r);
 60                   //不要返回
 61             }
 62             if (l == r) return;
 63             int mid = (l + r) >> 1;
 64             build(t->ch[0], l, mid);
 65             build(t->ch[1], mid + 1, r);
 66        }
 67        //t为现在的数将x的num改为val
 68        void insert(Node *&t, Node *&last, int x, int val){
 69             if (t == NULL){
 70                t = NEW(last->l, last->r);
 71             }
 72             if (t->l == x && t->r == x) {t->num = val; return;}
 73             int mid = (t->l + t->r) >>1;
 74             if (x <= mid){
 75                   insert(t->ch[0], last->ch[0], x, val);
 76                   t->ch[1] = last->ch[1];
 77             }
 78             if (x > mid){
 79                   insert(t->ch[1], last->ch[1], x, val);
 80                   t->ch[0] = last->ch[0];
 81             }
 82        }
 83        //直接修改,不是可持久化的,节省空间
 84        /*void change(Node *&t, int x, int val){
 85             if (t->l == x && t->r == x) {t->num = val;return;}
 86             int mid = (t->l + t->r) >> 1;
 87             if (x <= mid) change(t->ch[0], x, val);
 88             if (x > mid) change(t->ch[1], x, val);
 89        }*/
 90        int get(int k, int x){//查找k时刻x的fa值
 91            Node *t = root[k];
 92            while (1){
 93                  if (t->l == x && t->r == x) break;
 94                  int mid = (t->l + t->r) >> 1;
 95                  if (x <= mid) t = t->ch[0];
 96                  else t = t->ch[1];
 97            }
 98            return t->num;
 99        }
100 }A;
101 int data[MAXN];//真正的操作次数
102 int cnt = 0;//cnt记录现在的状态
103 int BIGCNT;
104
105 int find(int x){
106     int tmp = A.get(cnt, x);
107     if (tmp < 0) return x;
108     else{
109          int tmp2 = find(tmp);
110          //A.insert(A.root[cnt + 1], A.root[cnt], x, tmp2);
111          //cnt++;
112          return tmp2;
113     }
114 }
115 //启发式合并
116 void merge(int x, int y){
117     //分别代表真实数量
118     int x_num = -A.get(cnt, x);
119     int y_num = -A.get(cnt ,y);
120     if (x_num > y_num){//将y合并到x上
121        //这里可以可持久化了
122        //A.root[cnt + 1] = NULL;
123        A.insert(A.root[BIGCNT + 1], A.root[cnt], x, -(x_num + y_num));
124        BIGCNT++;
125        //A.root[cnt + 1] = NULL;
126        A.insert(A.root[BIGCNT + 1], A.root[cnt], y, x);
127        BIGCNT++;
128     }else{
129        //A.root[cnt + 1] = NULL;
130        A.insert(A.root[BIGCNT + 1], A.root[cnt], y, -(x_num + y_num));
131        BIGCNT++;
132        //A.root[cnt + 1] = NULL;
133        A.insert(A.root[BIGCNT + 1], A.root[cnt], x, y);
134        BIGCNT++;
135        //printf("%d %d %d\n", x, y, find(x));
136     }
137 }
138 void work(){
139      int z = 1;//记录操作的
140      data[0] = 0;
141      cnt = 0;
142      BIGCNT = 0;
143      scanf("%d%d", &n, &m);
144      A.init();
145      for (int i = 1; i <= m; i++){
146          int t;
147          scanf("%d", &t);
148          if (t == 2){
149             int c;
150             scanf("%d", &c);//回到c时刻即操作之后
151             if (c == 2)
152             printf("");
153             cnt = data[c];
154          }else if (t == 1){
155             int a, b;
156             scanf("%d%d", &a, &b);
157             int xa = find(a), xb = find(b);
158             if (xa == xb) {data[i] = cnt;continue;}
159             merge(xa, xb);
160             cnt = BIGCNT;
161          }else{
162             int a, b;
163             scanf("%d%d", &a, &b);
164             if (find(a) == find(b)) printf("1\n");
165             else printf("0\n");
166          }
167          data[i] = cnt;
168      }
169      //printf("%d", data[6]);
170 }
171
172 int main(){
173
174
175     work();
176     return 0;
177 }

时间: 2024-08-29 23:51:16

【BZOJ3673】【可持久化并查集】可持久化并查集 by zky的相关文章

JMS消息持久化,将ActiveMQ消息持久化到mySql数据库中

ActiveMQ5.8.0版本采用kahadb作为默认的消息持久化方式.使用默认的持久化机制,我们不容易直接看到消息究竟是如何持久的.ActiveMQ提供的JDBC持久化机制,能够将持久化信息存储到数据库.通过查看数据库中ActiveMQ生成的表结构和存储的数据,能够帮助我们更好的了解消息的持久化机制.现在介绍如何配置activemq,将数据持久化到mysql中. 1.配置activeMQ需要的mySql数据源 为了能够使用JDBC访问mysql数据库,显然必须要配置消息服务器的数据库源.在ac

k8s数据持久化之statefulset的数据持久化,并自动创建PV与PVC

一:Statefulset StatefulSet是为了解决有状态服务的问题,对应的Deployment和ReplicaSet是为了无状态服务而设计,其应用场景包括:1.稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现2.稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现3.有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依

从单机到集群会话的管理之集群模式二(更大的集群)

<从单机到集群会话的管理之集群模式一>中讲到的全节点复制的网络流量随节点数量增加呈平方趋势增长,也正是因为这个因素导致无法构建较大规模的集群,为了使集群节点能更加大,首要解决的就是数据复制时流量增长的问题,下面将介绍另外一种会话管理方式,每个会话只会有一个备份,它使会话备份的网络流量随节点数量的增加呈线性趋势增长,大大减少了网络流量和逻辑操作,可构建较大的集群. 下面看看这种方式具体的工作机制,集群一般是通过负载均衡对外提供整体服务,所有节点被隐藏在后端组成一个整体.前面各种模式的实现都无需负

分布式缓存技术redis学习系列(四)——redis高级应用(集群搭建、集群分区原理、集群操作)

本文是redis学习系列的第四篇,前面我们学习了redis的数据结构和一些高级特性,点击下面链接可回看 <详细讲解redis数据结构(内存模型)以及常用命令> <redis高级应用(主从.事务与锁.持久化)> 本文我们继续学习redis的高级特性--集群.本文主要内容包括集群搭建.集群分区原理和集群操作的学习. Redis集群简介 Redis 集群是3.0之后才引入的,在3.0之前,使用哨兵(sentinel)机制(本文将不做介绍,大家可另行查阅)来监控各个节点之间的状态.Redi

redis高级应用(集群搭建、集群分区原理、集群操作)

文章主目录 Redis集群简介 Redis集群搭建 Redis集群分区原理 集群操作 参考文档 本文是redis学习系列的第四篇,前面我们学习了redis的数据结构和一些高级特性,点击下面链接可回看 <详细讲解redis数据结构(内存模型)以及常用命令> <redis高级应用(主从.事务与锁.持久化)> 本文我们继续学习redis的高级特性--集群.本文主要内容包括集群搭建.集群分区原理和集群操作的学习. 回到顶部 Redis集群简介 Redis 集群是3.0之后才引入的,在3.0

mongodb3.6集群搭建:分片+副本集

mongodb是最常用的noSql数据库,在数据库排名中已经上升到了前五.这篇文章介绍如何搭建高可用的mongodb(分片+副本)集群. 在搭建集群之前,需要首先了解几个概念:路由,分片.副本集.配置服务器等.相关概念mongodb集群架构图: 从图中可以看到有四个组件:mongos.config server.shard.replica set.mongos,数据库集群请求的入口,所有的请求都通过mongos进行协调,不需要在应用程序添加一个路由选择器,mongos自己就是一个请求分发中心,它

linux集群系列(1) --- Linux集群系统基础

一.简介     1.1. Linux集群系统包括集群节点和集群管理器两部分. 集群节点有时简称为节点.服务器或服务器节点,是提供处理资源的系统,它进行集群的实际工作.一般来讲,它必须进行配置才能成为集群的一部分,也必须运行集群的应用软件.应用软件可以是专用于集群的软件,也可以是设计用于分布式系统的标准软件. Linux集群管理器则是将节点捆绑在一起,以构成单一系统外观的逻辑结构,它用于将任务分解到所有的节点.集群因多种不同的原因而有着不同的类型,建立Linux集群的最直接原因是共享CPU资源,

高可用集群HA之双机集群

HA:High Availability  高可用性:主要目的就是让运行在服务器上的服务尽可能减少的中断的技术,保证服务运行的连续性:原理如上图所示,本文实现双机集群系统,首先通关管理虚拟机LUCI服务对ClusterVM1.ClusterVM2进行管理,维护等工作,而他们之间沟通的桥梁是RICCI服务,所以ClusterVM1.ClusterVM2均安装RICCI服务.主要工作原理是ClusterVM1.ClusterVM2构成集群的双机,将其中一台作为活动机,也就是运行服务的主机(Clust

利用Docker部署mongodb集群--分片与副本集

环境 Docker version 1.6.2  mongodb 3.0.4 第一步  编写Dockerfile并生成镜像 主意包含两个Dockerfile镜像,一个mongod的,一个mongos(在集群中负责路由) 编写Mongod的Dockerfile: FROM ubuntu:14.04 RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 ENV MONGO_MAJOR 3.0 RUN ech

从单机到集群会话的管理之集群模式一

为什么要使用集群?主要有两方面原因:一是对于一些核心系统要求长期不能中断服务,为了提供高可用性我们需要由多台机器组成的集群:另外一方面,随着访问量越来越大且业务逻辑越来越复杂,单台机器的处理能力已经不足以处理如此多且复杂的逻辑,于是需要增加若干台机器使整个服务处理能力得到提升. 如果说一个web应用不涉及会话的话,那么做集群是相当简单的,因为节点都是无状态的,集群内各个节点无需互相通信,只需要将各个请求均匀分配到集群节点即可.但基本所有web应用都会使用会话机制,所以做web应用集群时整个难点在