洛谷题目传送门

LCT维护子树信息常见套路详见我的总结

闲话

题目摘自WC模拟试题(by Philipsweng),原题目名Wander,“山村游历”是自己搞出来的中文名。

数据自测,如有问题欢迎反馈

对耐心的人来说,这道题是个裸题(当我什么也没说)

题面

题目描述

在一个偏远的小镇上,有一些落后的山村。山村之间通过一些道路来连接。当然有的山村可能不连通。

一年当中会发生很多大事,比如说有人提议要在山村\(i\)与\(j\)之间修建一条道路,也有人觉得山村\(i\)和\(j\)之间的道路需要被拆掉。

由于小镇的落后,镇长不会允许存在两个山村\(i,j\),他们存在超过一条路径到达对方。也就是说,假如在修建山村\(i,j\)之间的道路之前,它们已经连通了,那么这条道路就不会被修建。

但拆除道路就不一样了。假如有人建议拆除连接\(i,j\)的道路,并且\(i,j\)的确有道路相连的话,镇长就会把它拆掉。

除了道路的修建与拆迁外,热情的山村人也会到处拜访其他人。有的时候来自山村\(i\)的人会想到山村\(j\)玩。

但山村人都是不识路的,那怎么办?他们有一种奇怪的遍历方式。

设一次旅行的起点为S,终点为T,点u的边集为V(i),那么这个走路过程可以用下面的伪代码来表示。

  1. function DFS(u)
  2. if u==T then
  3. finish search
  4. flag[u]<-true
  5. random shuffle the vertices order in V(u)
  6. //here all permutations have equal probability to be chosen
  7. for i in V(u) do
  8. if flag[i]==false then
  9. count++;
  10. DFS(i);
  11. count++;

最后count就是这次旅行所花时间。

很显然对于一次旅行,count可能有多种取值,那么对于这次旅行时间的评估,就是count的期望。

对于每次旅行,你都要告诉山村人他这次旅行时间的评估是多少。

一开始所有的山村之间都是没有道路连接的。

输入输出格式

输入格式:

第一行两个整数\(N,Q\),表示小镇上总共有\(N\)个山村,一年中发生了\(Q\)件大事。

接下来\(Q\)行,每行包括三个整数\(type,u,v\)。

  • 若\(type=0\),表示有人建议在\(u,v\)之间修建一条道路。
  • 若\(type=1\)表示有人建议拆除\(u,v\)之间的道路。
  • 若\(type=2\),表示山村人要进行一次\(u\)出发到\(v\)结束的旅行。

输出格式:

输出共\(Q\)行。

对于第i件大事,若\(type=0\)或\(1\),假如这件大事能完成,则输出OK,否则输出ILLEGAL。若\(type=2\) ,假如这次旅行能到达终点,则输出对应的时间评估,否则输出ILLEGAL。

对于每个时间评估,输出保留4位小数。

输入输出样例

输入样例#1:

4 9

0 1 2

0 2 4

0 4 1

2 1 4

0 2 3

2 1 4

1 4 1

1 3 2

2 1 3

输出样例#1:

OK

OK

ILLEGAL

2.0000

OK

3.0000

ILLEGAL

OK

ILLEGAL

说明

对于\(100\%\)的数据,\(N≤100000,Q≤300000,1≤u,v≤N\)

思路分析

这是LCT题目很明显吧,赤裸裸地道出了这个小镇的穷,连多修一条路都舍不得

我们只要弄明白答案是要维护什么东西就好了。

我费了好大劲,终于搞懂了这个奇葩的游历方式(或许用C++描述会更舒服一些)

  1. int count=0;
  2. void dfs(int u)
  3. {
  4. if(u==T)cout<<count,exit(0);
  5. flag[u]=true;
  6. random_shuffle(V[u],V[u]+len[u]);
  7. for(i=0;i<len[u];++i)
  8. if(!flag[V[i]])count++,dfs(V[i]);
  9. count++;
  10. }

简单的说,就是只要找不到终点,就会选一条没走过的边,一直走下去,直到碰到死路才回来。而count就好比他走一步的时间加上走不通退回来的时间。

那么把起点和终点所在的树搞出来,那么每个点都会有若干个子树,就好像下面这样(绿色三角形表示子树,蓝色点表示\(S->T\)的路径,为了使路径突出,这里搞得不像一棵树了)



那么,假如有概率选择了某个子树的话,那人一定会把整个子树走完并且回来对吧。假如选择了路径上的边继续走下去,那么就再也不会回去了,以前没走完的子树也一定不会走了。

于是问题简化了。设每个子树在选择沿着\(S->T\)的路径继续走下去之前被选择的概率为\(p\),那么我们要求的期望大概可以表达成

\(\sum_{j=1}^n2p_{s_j}size_{s_j}+\sum_{i=1}^m\sum_{j=1}^n2p_{s_{ij}}size_{a_{ij}}\)

仍然不能用LCT维护,我们还需要知道\(p\)。

注意这是随机的排列。对于每个排列,有且仅有另一个排列与其顺序相反。如果有一个排列,某一子树排在了路径边的前面(需要计算\(size\)),那么必定有且仅有另一个对应的排列使得该子树排在路径边的后面(不需要计算\(size\))。由于这种等概率的对应关系,\(p={1\over2}\)得证。

\(1\over2\)乘上系数\(2\),不就变成了\(\sum_{j=1}^nsize_{s_j}+\sum_{i=1}^m\sum_{j=1}^nsize_{a_{ij}}\)么。哈哈哈哈全是整数!?别被保留四位小数吓到以为要搞什么概率期望DP高斯消元啦(其实我什么都不会)

用LCT维护虚子树size和原树总size,那么这个式子还不如直接变成该原树的总大小减去T的虚子树总大小再减\(1\)(T的大小),或者\(split(T,S)\)(以S为根),变成原树的总大小减去以T为根的子树总大小。

代码在此(看懂了题目,代码真的不需要什么注释了。。。。。。)

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #define R register int
  4. #define I inline
  5. const int N=100009;
  6. int f[N],c[N][2],si[N],s[N];
  7. bool r[N];
  8. #define lc c[x][0]
  9. #define rc c[x][1]
  10. I bool nroot(R x){return c[f[x]][0]==x||c[f[x]][1]==x;}
  11. I void pushup(R x){
  12. s[x]=s[lc]+s[rc]+si[x]+1;
  13. }
  14. I void pushdown(R x){
  15. if(r[x]){
  16. R t=lc;lc=rc;rc=t;
  17. r[lc]^=1;r[rc]^=1;r[x]=0;
  18. }
  19. }
  20. I void pushall(R x){
  21. if(nroot(x))pushall(f[x]);
  22. pushdown(x);
  23. }
  24. I void rotate(R x){
  25. R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
  26. if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
  27. f[w]=y;f[y]=x;f[x]=z;
  28. pushup(y);
  29. }
  30. /*
  31. I void splay(R x){
  32. R y;
  33. pushall(x);
  34. while(nroot(x)){
  35. y=f[x];
  36. if(nroot(y=f[x]))
  37. rotate((c[y][0]==x)^(c[f[y]][0]==y)?y:x);
  38. rotate(x);
  39. }
  40. pushup(x);
  41. }
  42. */
  43. I void splay(R x){
  44. pushall(x);
  45. while(nroot(x))rotate(x);
  46. pushup(x);
  47. }
  48. I void access(R x){
  49. for(R y=0;x;x=f[y=x]){
  50. splay(x);
  51. si[x]+=s[rc];
  52. si[x]-=s[rc=y];
  53. pushup(x);
  54. }
  55. }
  56. I void makeroot(R x){
  57. access(x);splay(x);
  58. r[x]^=1;
  59. }
  60. I int findroot(R x){
  61. access(x);splay(x);
  62. while(lc)x=lc;
  63. return x;
  64. }
  65. I void split(R x,R y){
  66. makeroot(x);
  67. access(y);splay(y);
  68. }
  69. I bool link(R x,R y){
  70. makeroot(x);
  71. if(findroot(y)==x)return 0;
  72. si[f[x]=y]+=s[x];
  73. pushup(y);
  74. return 1;
  75. }
  76. I bool cut(R x,R y){
  77. makeroot(x);
  78. if(findroot(y)!=x||f[x]!=y||c[x][1])return 0;
  79. f[x]=c[y][0]=0;
  80. return 1;
  81. }
  82. #define G ch=getchar()
  83. #define in(z) G;\
  84. while(ch<'-')G;\
  85. z=ch&15;G;\
  86. while(ch>'-')z*=10,z+=ch&15,G;
  87. int main(){
  88. register char ch;
  89. R n,q,type,u,v;
  90. in(n);in(q);
  91. for(R i=1;i<=n;++i)s[i]=1;
  92. while(q--){
  93. in(type);in(u);in(v);
  94. if(type<2)puts((type?cut(u,v):link(u,v))?"OK":"ILLEGAL");
  95. else{
  96. split(u,v);
  97. if(findroot(v)!=u)puts("ILLEGAL");
  98. else printf("%d.0000\n",s[v]-si[v]-1);
  99. }
  100. }
  101. return 0;
  102. }

洛谷U19464 山村游历(Wander)(LCT)的更多相关文章

  1. 洛谷U19464 山村游历(Wander)(LCT,Splay)

    洛谷题目传送门 LCT维护子树信息常见套路详见我的总结 闲话 题目摘自WC模拟试题(by Philipsweng),原题目名Wander,"山村游历"是自己搞出来的中文名. 数据自 ...

  2. 洛谷.U19464.山村游行wander(LCT 伪期望)

    题目链接 题意: 森林,动态建边.删边,询问从S开始走到T的期望时间.走位: 每次人会随机地选一条未走过的边走,走到无路可走,再退回.这样直到终点T.走一条边.从一条边退回都花费时间1. 题目特点是走 ...

  3. U19464 山村游历(Wander) LCT维护子树大小

    \(\color{#0066ff}{ 题目描述 }\) 在一个偏远的小镇上,有一些落后的山村.山村之间通过一些道路来连接.当然有的山村可能不连通. 一年当中会发生很多大事,比如说有人提议要在山村\(i ...

  4. 洛谷.4172.[WC2006]水管局长(LCT Kruskal)

    题目链接 洛谷(COGS上也有) 不想去做加强版了..(其实处理一下矩阵就好了) 题意: 有一张图,求一条x->y的路径,使得路径上最长边尽量短并输出它的长度.会有<=5000次删边. 这 ...

  5. 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)

    洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...

  6. 洛谷P3950 部落冲突(LCT)

    洛谷题目传送门 最无脑LCT题解,Dalao们的各种算法都比这个好多啦... 唯一的好处就是只管码代码就好了 开战cut,停战link,询问findroot判连通性 太无脑,应该不用打注释了.常数大就 ...

  7. 【题解】洛谷P4145 花神游历各国(线段树)

    洛谷P4145:https://www.luogu.org/problemnew/show/P4145 思路 这道题的重点在于sqrt(1)=1 一个限制条件 与正常线段树不同的是区间修改为开方 那么 ...

  8. 洛谷P3348 [ZJOI2016]大森林 [LCT]

    传送门 刷了那么久水题之后终于有一题可以来写写博客了. 但是这题太神仙了我还没完全弄懂-- upd:写完博客之后似乎懂了. 思路 首先很容易想到\(O(n^2\log n)\)乘上\(O(\frac{ ...

  9. 洛谷P2147 [SDOI2008] 洞穴勘探 [LCT]

    题目传送门 洞穴勘探 题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道 ...

随机推荐

  1. 发布.net core到Centos7

    用到的软件如下 xshell,xftp,vs2017.3,centos 7.3 64位 安装环境 aliyun centos 7.3 64位 安装.net core 2.0 依赖的组件 yum ins ...

  2. test_maven_实现表单验证

    这篇文章是我的上一篇文章的续集,如未看过,可看一下,上面的test_maven再继续看这个 这篇文章主要是阐述使用struts实现表单验证的功能. 1.首先了解actionContext:Action ...

  3. Redis数据库的安装与基本应用

    一:了解NoSQL 1:介绍:Nosql的全称是Not Only Sql,这个概念早起就有人提出,在09年的时候比较火.Nosql指的是非关系型数据库,而我们常用的都是关系型数据库.就像我们常用的my ...

  4. 20155333 《网络对抗》 Exp8 Web基础

    20155333 <网络对抗> Exp8 Web基础 基础问题 (1)什么是表单? 表单在网页中主要负责数据采集功能. 一个表单有三个基本组成部分: 表单标签,这里面包含了处理表单数据所用 ...

  5. WPF编程,通过Double Animation动态更改控件属性的一种方法。

    原文:WPF编程,通过Double Animation动态更改控件属性的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/a ...

  6. mfc 类三种继承方式下的访问

    知识点 public private protected 三种继承方式 三种继承方式的区别 public 关键字意味着在其后声明的所有成员及对象都可以访问. private 关键字意味着除了该类型的创 ...

  7. PowerBI开发 第一篇:设计PowerBI报表

    PowerBI是微软新一代的交互式报表工具,把相关的静态数据转换为酷炫的可视化的,能够根据filter条件,对数据执行动态筛选,从不同的角度和粒度上分析数据.PowerBI主要由两部分组成:Power ...

  8. Egret(白鹭引擎)——Egret+fairyGui 实战项目入门

    前言 一行白鹭上青天 需求 最近,我们老板刷刷的为了省事,给美术减压(背景有点长,不说了). 美术出 fairygui,我需要在网页上看到实时操作,并且看到效果! 需求分析 这怕是要了我的狗命啊,但是 ...

  9. Vue 入门之 Vuex 实战

    Vue 入门之 Vuex 实战 引言 Vue 组件化做的确实非常彻底,它独有的 vue 单文件组件也是做的非常有特色.组件化的同时带来的是:组件之间的数据共享和通信的难题. 尤其 Vue 组件设计的就 ...

  10. php OPcache

    众所周知php是一种解释型语言,它的执行可分为如下几个流程: Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens) Parsing, 将Tokens转换成简单而有意义的表达式 ...