【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询
题目描述
输入
接下来n-1行,每行包含两个整数x和y,表示局域网中编号为x和y的计算机之间有网线直接相连。
接下来m行,每行包含一个操作或者询问,格式如问题描述中所述。
输出
样例输入
8 6
1 2
1 3
2 8
3 4
3 5
3 6
4 7
REQUEST 7
RELEASE 3
REQUEST 3
RECENTER 5
RELEASE 2
REQUEST 1
样例输出
4.0000000000
2.0000000000
1.3333333333
题解
LCT+树上倍增+DFS序+树状数组区间修改区间查询
这也是一道神题了。。。不查题解真的想不到。。。
首先同种颜色的一定是一条链。
然后如果把同种颜色的边看作实边,不同种颜色的边看作虚边的话,
一次感染就是LCT中的access操作,代价就是虚边数量+1。。。
(估计出题人是根据access操作的方法才出的这题吧。。。正常人根本想不到是LCT啊。。。)
一次RECENTER操作就是makeroot(makeroot自带一次access,就对应了题目的再感染一次。。。)
所以一个点的答案只与虚边数量有关,而只有虚边变化(access)时某些点的答案才会变化。
考虑加虚边答案怎么变化:一个点到其父亲节点加了一条虚边,那么其子树内所有节点到根节点都需要经过这一条虚边,该子树内答案+1。删虚边同理。
这里要注意一个问题:Splay的根节点不是这条链上深度最小的点,最左边的节点才是要更新子树的节点。因此在更新子树时还要找Splay中最左边的节点,同时不要忘了pushdown。
由于本题的根是变化的,因此参考 bzoj3083遥远的国度 ,将子树转化为dfs序上的至多两端区间,将得到的区间+1或-1。其中找第一个子节点的过程可以使用树上倍增实现。
因为本体略卡常,所以采用了树状数组区间修改区间查询,方法参考 bzoj3132上帝造题的七分钟 。
查询时同理,直接把区间和求出来即可。
时间复杂度$O(n\log^2n*不知多大的常数)=O(能过)$
#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
typedef long long ll;
struct lct
{
int fa , c[2] , rev;
}a[N];
int n , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][20] , deep[N] , pos[N] , last[N] , tot , log[N] , root = 1;
ll f[N] , g[N];
char str[15];
inline void modify(int x , int a)
{
int i;
for(i = x ; i <= n ; i += i & -i) f[i] += a , g[i] += x * a;
}
inline ll query(int x)
{
int i;
ll s1 = 0 , s2 = 0;
for(i = x ; i ; i -= i & -i) s1 += f[i] , s2 += g[i];
return (x + 1) * s1 - s2;
}
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x)
{
int i;
pos[x] = ++tot;
for(i = 1 ; (1 << i) <= 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 , a[to[i]].fa = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]);
last[x] = tot;
modify(pos[x] , 1) , modify(last[x] + 1 , -1);
}
inline int find(int x , int y)
{
int i;
for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
if((1 << i) < deep[x] - deep[y])
x = fa[x][i];
return x;
}
inline void rever(int x)
{
swap(a[x].c[0] , a[x].c[1]) , a[x].rev ^= 1;
}
inline void pushdown(int x)
{
if(a[x].rev) rever(a[x].c[0]) , rever(a[x].c[1]) , a[x].rev = 0;
}
inline bool isroot(int x)
{
return a[a[x].fa].c[0] != x && a[a[x].fa].c[1] != x;
}
void update(int x)
{
if(!isroot(x)) update(a[x].fa);
pushdown(x);
}
inline void rotate(int x)
{
int y = a[x].fa , z = a[y].fa , l = (a[y].c[1] == x) , r = l ^ 1;
if(!isroot(y)) a[z].c[a[z].c[1] == y] = x;
a[x].fa = z , a[y].fa = x , a[a[x].c[r]].fa = y , a[y].c[l] = a[x].c[r] , a[x].c[r] = y;
}
inline void splay(int x)
{
int y , z;
update(x);
while(!isroot(x))
{
y = a[x].fa , z = a[y].fa;
if(!isroot(y)) rotate((a[y].c[0] == x) ^ (a[z].c[0] == y) ? x : y);
rotate(x);
}
}
inline void treemodify(int x , int v)
{
if(!x) return;
int y;
while(a[x].c[0]) pushdown(x) , x = a[x].c[0];
if(root == x) modify(1 , v);
else if(pos[root] < pos[x] || pos[root] > last[x]) modify(pos[x] , v) , modify(last[x] + 1 , -v);
else y = find(root , x) , modify(1 , v) , modify(pos[y] , -v) , modify(last[y] + 1 , v);
}
inline double treequery(int x)
{
int y;
if(root == x) return (double)query(n) / n;
else if(pos[root] < pos[x] || pos[root] > last[x]) return (double)(query(last[x]) - query(pos[x] - 1)) / (last[x] - pos[x] + 1);
else
{
y = find(root , x);
return (double)(query(n) - query(last[y]) + query(pos[y] - 1)) / (n - last[y] + pos[y] - 1);
}
}
inline void access(int x)
{
int t = 0 , y;
while(x) splay(x) , treemodify(t , -1) , y = a[x].c[1] , a[x].c[1] = t , treemodify(y , 1) , t = x , x = a[x].fa;
}
inline void makeroot(int x)
{
access(x) , splay(x) , rever(x) , root = x;
}
int main()
{
int m , i , x , y;
scanf("%d%d" , &n , &m);
for(i = 2 ; i <= n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x) , log[i] = log[i >> 1] + 1;
dfs(1);
while(m -- )
{
scanf("%s%d" , str , &x);
if(str[2] == 'L') access(x);
else if(str[2] == 'C') makeroot(x);
else printf("%.10lf\n" , treequery(x));
}
return 0;
}
【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询的更多相关文章
- cf983E NN Country (倍增+dfs序+树状数组)
首先可以求出从某点做$2^k$次车能到的最浅的点,这个只要dfs一下,把它的孩子能到的最浅的点更新过来就可以 然后倍增地往上跳,不能跳到lca的上面,记录坐车的次数ans 此时有三种情况(设最远能跳到 ...
- bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroo ...
- BZOJ4999 This Problem Is Too Simple!(树上差分+dfs序+树状数组)
对每个权值分别考虑.则只有单点加路径求和的操作.树上差分转化为求到根的路径和,子树加即可.再差分后bit即可.注意树上差分中根的父亲是0,已经忘了是第几次因为这个挂了. #include<ios ...
- 【bzoj4009】[HNOI2015]接水果 DFS序+树上倍增+整体二分+树状数组
题目描述 给出一棵n个点的树,给定m条路径,每条路径有一个权值.q次询问求一个路径包含的所有给定路径中权值第k小的. 输入 第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数. 接下来n ...
- 【bzoj2819】Nim DFS序+树状数组+倍增LCA
题目描述 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可以不取.谁不能取谁输.这个游戏是有必胜策略 ...
- 【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树
题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高 ...
- HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...
- 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- 2018.10.20 NOIP模拟 巧克力(trie树+dfs序+树状数组)
传送门 好题啊. 考虑前面的32分,直接维护后缀trietrietrie树就行了. 如果#号不在字符串首? 只需要维护第一个#前面的字符串和最后一个#后面的字符串. 分开用两棵trie树并且维护第一棵 ...
随机推荐
- vue-wechat-title
html中的title安装:npm install vue-wechat-title --save1.在mian.js中//网页titleimport VueTitle from 'vue-wecha ...
- 大白话讲解BP算法(转载)
最近在看深度学习的东西,一开始看的吴恩达的UFLDL教程,有中文版就直接看了,后来发现有些地方总是不是很明确,又去看英文版,然后又找了些资料看,才发现,中文版的译者在翻译的时候会对省略的公式推导过程进 ...
- 总结ing
1,iOS的GCD中如何关闭或者杀死一个还没执行完的后台线程? 举例来说,我通过导航进入到了一个视图,这个视图加载的时候会新建一个线程在后台运行,假设这个线程需要从网络中读取许多数据,需要一定的时间, ...
- tree树形
/** * tree * @param menuBeans * @param pid * @return */ public JSON makeTree(List<MenuBean& ...
- vue中登录模块的插件封装
一个电商城的项目,场景是:在未登录的情况下点击收藏或者加入购物车等操作,执行一个方法如this.$login()来动态插入登录组件. 第一步:写好关于这个登录弹窗的单文件组件 loginBox.vue ...
- java高并发之CountDownLatch,CyclicBarrier和join
晚上打车回家,在车上看到一篇文章<22岁大学生获谷歌天价Offer,年薪千万!>,讲的是印度一个22岁大学生多次参加ACM大赛,开源多个项目,以非常牛逼的履历通过了谷歌的AI测试,斩获谷歌 ...
- django+xadmin在线教育平台(十五)
7-4 课程机构列表页数据展示2 前去html中进行数据填充 mark 可以看到所有城市是通过a标签,当前选中城市为active. mark 之后把下面的写死的城市删除掉. mark 这时 ...
- Docker自学纪实(六)搭建docker私有仓库
docker的镜像仓库分两种:一种是从官方公有仓库拉取:还有就是自己搭建私有仓库.官方的镜像仓库是面对整个应用市场的:私有仓库一般用于公司内部,就是公司项目自身所需的镜像.搭建私有仓库有什么好处?私有 ...
- 6-1 md5加密
1.导入hashlib模块,使用它的md5方法进行加密 import hashlib # import md5 python2 s = 'admin123' # .将字符串类型转换成byte类型才能加 ...
- ES6笔记04-class的基本语法
JavaScript 语言中,生成实例对象的传统方法是通过构造函数. ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板.通过class关键字,可以定义类. clas ...