当前位置: 首页 > news >正文

【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并

题目描述

输入

第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。 
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。 
接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

输出

对于每一个第一类操作,输出一个非负整数表示答案。 

样例输入

1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6

样例输出

2
2
1
4
2


题解

倍增LCA+主席树+启发式合并

如果没有连边操作,那么本题同 bzoj2588 。

好在本题的n只有80000,所以我们可以使用一些高(qi)端(ji)姿(yin)势(qiao)来解决。

由于只有连边没有删边,所以可以使用启发式合并,暴力将较小的树连到较大的树上,从连接点开始再dfs一遍更新fa和deep。

同时需要记录每棵树的大小,相当于记录每个点的树根。

然后就是建树,求LCA,求出答案。

这里需要注意的一点是,对于不同的倍增LCA的写法,如果写法中利用到f[x][...]=0,那么务必在连边时将原来的f数组清空,否则当原深度大于新深度时会WA->RE。

#include <cstdio>
#include <algorithm>
#define N 80010
using namespace std;
int n , w[N] , a[N] , ref[N] , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][20] , deep[N] , log[N] , bl[N] , si[N];
int ls[N << 8] , rs[N << 8] , sum[N << 8] , root[N] , tot;
char str[5];
void add(int x , int y)
{
	to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void insert(int p , int l , int r , int x , int &y)
{
	if(!y) y = ++tot;
	sum[y] = sum[x] + 1;
	if(l == r) return;
	int mid = (l + r) >> 1;
	if(p <= mid) rs[y] = rs[x] , insert(p , l , mid , ls[x] , ls[y]);
	else ls[y] = ls[x] , insert(p , mid + 1 , r , rs[x] , rs[y]);
}
int query(int p , int l , int r , int a , int b , int c , int d)
{
	if(l == r) return ref[l];
	int mid = (l + r) >> 1;
	if(sum[ls[a]] + sum[ls[b]] - sum[ls[c]] - sum[ls[d]] >= p) return query(p , l , mid , ls[a] , ls[b] , ls[c] , ls[d]);
	else return query(p - sum[ls[a]] - sum[ls[b]] + sum[ls[c]] + sum[ls[d]] , mid + 1 , r , rs[a] , rs[b] , rs[c] , rs[d]);
}
void dfs(int x , int r)
{
	int i;
	bl[x] = r , si[r] ++ ;
	insert(w[x] , 1 , n , root[fa[x][0]] , root[x]);
	for(i = 1 ; i <= log[deep[x]] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
	for(i = head[x] ; i ; i = next[i])
		if(to[i] != fa[x][0])
			fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i] , r);
}
int lca(int x , int y)
{
	int i;
	if(deep[x] < deep[y]) swap(x , y);
	for(i = log[deep[x] - deep[y]] ; i >= 0 ; i -- )
		if(deep[x] - deep[y] >= (1 << i))
			x = fa[x][i];
	for(i = log[deep[x]] ; i >= 0 ; i -- )
		if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i])
			x = fa[x][i] , y = fa[y][i];
	return x == y ? x : fa[x][0];
}
int main()
{
	int m , q , i , t , x , y , z , last = 0;
	scanf("%*d%d%d%d" , &n , &m , &q);
	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &w[i]) , a[i] = w[i];
	sort(a + 1 , a + n + 1);
	for(i = 1 ; i <= n ; i ++ ) t = w[i] , w[i] = lower_bound(a + 1 , a + n + 1 , w[i]) - a , ref[w[i]] = t;
	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
	log[0] = -1;
	for(i = 2 ; i <= n ; i ++ ) log[i] = log[i >> 1] + 1;
	for(i = 1 ; i <= n ; i ++ ) if(!fa[i][0]) dfs(i , i);
	while(q -- )
	{
		scanf("%s%d%d" , str , &x , &y) , x ^= last , y ^= last;
		if(str[0] == 'Q')
		{
			scanf("%d" , &z) , z ^= last , t = lca(x , y);
			printf("%d\n" , last = query(z , 1 , n , root[x] , root[y] , root[t] , root[fa[t][0]]));
		}
		else
		{
			if(si[bl[x]] < si[bl[y]]) swap(x , y);
			fa[y][0] = x , deep[y] = deep[x] + 1 , dfs(y , bl[x]) , add(x , y) , add(y , x);
		}
	}
	return 0;
}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/7110368.html

相关文章:

  • 电子商务推荐算法
  • 每个人必须知道的社会生活十二大著名法则
  • 如何更改PHPCMS网站后台标题(title)
  • 数据挖掘常见软件
  • sql语句中like的用法详细解析
  • 世界上应该珍惜的五个人
  • firewall 相关命令
  • 数据挖掘方法论crisp-DM
  • 欢迎使用CSDN-markdown编辑器
  • 数据挖掘方法论-SEMMA
  • C++按行读取和写入文件
  • 数据挖掘常见分析方法
  • Xcode多种Build Configuration配置使用
  • 统计分析方法分类
  • oracle sql*plus
  • 【347天】每日项目总结系列085(2018.01.18)
  • canvas 高仿 Apple Watch 表盘
  • docker容器内的网络抓包
  • flask接收请求并推入栈
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • Java 网络编程(2):UDP 的使用
  • java中的hashCode
  • JS题目及答案整理
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • Lucene解析 - 基本概念
  • MobX
  • nodejs实现webservice问题总结
  • Objective-C 中关联引用的概念
  • Redis中的lru算法实现
  • RxJS: 简单入门
  • SpringBoot 实战 (三) | 配置文件详解
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • vue 配置sass、scss全局变量
  • vue-router 实现分析
  • 成为一名优秀的Developer的书单
  • 对象引论
  • 服务器之间,相同帐号,实现免密钥登录
  • 复杂数据处理
  • 关于 Cirru Editor 存储格式
  • 机器学习中为什么要做归一化normalization
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 记录一下第一次使用npm
  • 开发基于以太坊智能合约的DApp
  • 离散点最小(凸)包围边界查找
  • 删除表内多余的重复数据
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • ​水经微图Web1.5.0版即将上线
  • (1)常见O(n^2)排序算法解析
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (33)STM32——485实验笔记