3123: [Sdoi2013]森林

Time Limit: 20 Sec  Memory Limit: 512 MB

Description

Input

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

Output

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

Sample Input

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

Sample Output

2
2
1
4
2

HINT

对于第一个操作 Q 8 7 3,此时 lastans=0,所以真实操作为Q 8^0 7^0 3^0,也即Q 8 7 3。点8到点7的路径上一共有5个点,其权值为4 1 1 2 4。这些权值中,第三小的为 2,输出 2,lastans变为2。对于第二个操作 Q 3 5 1 ,此时lastans=2,所以真实操作为Q 3^2 5^2 1^2 ,也即Q 1 7 3。点1到点7的路径上一共有4个点,其权值为 1 1 2 4 。这些权值中,第三小的为2,输出2,lastans变为 2。之后的操作类似。

题解:

看到求k值,我们很容易想到主席树这种求区间k大值的工具(不了解树上主席树的同学可以看一下我之前的讲解http://www.cnblogs.com/LadyLex/p/7275164.html,再参考一下下面的代码)

但是,本题的合并操作给我们带来了麻烦,让我们无处下手。难道我们之间暴力添加吗?肯定会T。

所以我们考虑利用启发式合并,即把个数较小的树插入个数较大的树中。

启发式合并的操作听起来和暴力没有什么区别,但是它的复杂度是有保障的:

每次合并,新树的大小是原来较小树大小的二倍以上,因此最多需要logn次合并成了1棵树。

每次合并平均是(n/2)log权值的,因此总时间复杂度是O(nlognlog权值)的

如果离散化的话,跑的就更快了,大约O(nlog2n)(不过我自己的代码没有离散,233)

代码见下:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <vector>
  4. #include <algorithm>
  5. using namespace std;
  6. const int N=,MAXN=;
  7. int n,cnt,val[N],sum,adj[N],e;
  8. int origin[N],belong[N],size[N],deep[N];
  9. struct edge{int zhong,next;}s[N<<];
  10. inline void swap(int &a,int &b){int t=a;a=b;b=t;}
  11. inline void add(int qi,int zhong){s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
  12. int f[N][],bin[];
  13. inline void mission1(int x)
  14. {for(int i=;i<=;i++)f[x][i]=f[f[x][i-]][i-];}
  15. inline int LCA(int a,int b)
  16. {
  17. if(deep[a]<deep[b])swap(a,b);
  18. int cha=deep[a]-deep[b];
  19. for(int j=;~j;j--)if(cha&bin[j])a=f[a][j];
  20. if(a==b)return a;
  21. for(int j=;~j;j--)
  22. if(f[a][j]!=f[b][j])a=f[a][j],b=f[b][j];
  23. return f[a][];
  24. }
  25. struct node
  26. {
  27. int cnt;node *ch[];
  28. node(){cnt=;ch[]=ch[]=NULL;}
  29. inline void update(){cnt=ch[]->cnt+ch[]->cnt;}
  30. }*null=new node(),*root[N];
  31. inline node* newnode()
  32. {
  33. node *o=new node();
  34. o->ch[]=o->ch[]=null;
  35. return o;
  36. }
  37. inline int query(int x,int y,int k)
  38. {
  39. int lca=LCA(x,y),t=f[lca][],l=,r=MAXN;
  40. node *a=root[x],*b=root[y],*c=root[lca],*d=root[t];
  41. while(l<r)
  42. {
  43. int tmp=a->ch[]->cnt+b->ch[]->cnt-c->ch[]->cnt-d->ch[]->cnt,mi=(l+r)>>;
  44. if(tmp>=k)a=a->ch[],b=b->ch[],c=c->ch[],d=d->ch[],r=mi;
  45. else k-=tmp,a=a->ch[],b=b->ch[],c=c->ch[],d=d->ch[],l=mi+;
  46. }
  47. return r;
  48. }
  49. void insert(node *&a,node *b,int l,int r,int pos)
  50. {
  51. a->cnt=b->cnt+;
  52. int mi=(l+r)>>;
  53. if(l==r)return;
  54. if(pos<=mi)a->ch[]=b->ch[],a->ch[]=newnode(),insert(a->ch[],b->ch[],l,mi,pos);
  55. else a->ch[]=b->ch[],a->ch[]=newnode(),insert(a->ch[],b->ch[],mi+,r,pos);
  56. a->update();
  57. }
  58. void dfs1(int rt,int fa)
  59. {
  60. f[rt][]=fa;mission1(rt);
  61. sum++;deep[rt]=deep[fa]+;belong[rt]=cnt;
  62. insert(root[rt],root[fa],,MAXN,val[rt]);
  63. for(int i=adj[rt];i;i=s[i].next)
  64. if(s[i].zhong!=fa)dfs1(s[i].zhong,rt);
  65. }
  66. void dfs2(int rt,int fa,int anc)
  67. {
  68. f[rt][]=fa;deep[rt]=deep[fa]+;mission1(rt);belong[rt]=anc;
  69. insert(root[rt],root[fa],,MAXN,val[rt]);
  70. for(int i=adj[rt];i;i=s[i].next)
  71. if(s[i].zhong!=fa)dfs2(s[i].zhong,rt,anc);
  72. }
  73. int main()
  74. {
  75. null->ch[]=null->ch[]=null;
  76. bin[]=;for(int i=;i<=;i++)bin[i]=bin[i-]<<;
  77. int ans=,m,t,a,b,d;char c[];scanf("%d",&t);
  78. scanf("%d%d%d",&n,&m,&t);
  79. for(int i=;i<=n;i++)root[i]=newnode();
  80. for(int i=;i<=n;i++)scanf("%d",&val[i]);
  81. while(m--)scanf("%d%d",&a,&b),add(a,b),add(b,a);
  82. for(int i=;i<=n;i++)
  83. if(!belong[i])sum=,cnt++,dfs1(i,),origin[cnt]=i,size[cnt]=sum;
  84. while(t--)
  85. {
  86. scanf("%s%d%d",c,&a,&b);a^=ans,b^=ans;
  87. if(c[]=='Q')scanf("%d",&d),d^=ans,printf("%d\n",ans=query(a,b,d));
  88. else
  89. {
  90. add(a,b),add(b,a);
  91. if(size[belong[a]]>size[belong[b]])
  92. size[belong[a]]+=size[belong[b]],dfs2(b,a,belong[a]);
  93. else size[belong[b]]+=size[belong[a]],dfs2(a,b,belong[b]);
  94. }
  95. }
  96. }

[BZOJ3123][Sdoi2013]森林 主席树+启发式合并的更多相关文章

  1. [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

  2. 【BZOJ-3123】森林 主席树 + 启发式合并

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2738  Solved: 806[Submit][Status] ...

  3. Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...

  4. BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]

    3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...

  5. luoguP3302 [SDOI2013]森林 主席树 启发式合并

    题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...

  6. [SDOI2013]森林 主席树+启发式合并

    这题的想法真的很妙啊. 看到题的第一眼,我先想到树链剖分,并把\(DFS\)序当成一段区间上主席树.但是会发现在询问的时候,可能会非常复杂,因为你需要把路径拆成很多条轻链和重链,它们还不一定连续,很难 ...

  7. 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并

    我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时 ...

  8. BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并

    题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...

  9. P3302 [SDOI2013]森林(主席树+启发式合并)

    P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...

随机推荐

  1. memcached 查看所有的key

    1. cmd上登录memcache   1 > telnet 127.0.0.1 11211 2. 列出所有keys   1 2 3 4 stats items // 这条是命令 STAT it ...

  2. 将float转换为数据类型numeric时出现算术溢出错误

    今天修改数据库字段类型,把float转换成decimal类型. 找了好多资料都没从根本上解决问题.多亏了下面的这个blog http://blog.csdn.net/wangchao1982/arti ...

  3. 实战演示疑惑 mysql insert到底加什么锁

    innodb的事务隔离级别是可重复读级别且innodb_locks_unsafe_for_binlog禁用,也就是说允许next-key lock 实验来自网上. ( 如果你没有演示出来,请check ...

  4. 工作中遇到的问题收集--.NET

    一.拒绝访问 temp 目录.用来运行 XmlSerializer 的标识“IIS APPPOOL\MZJYMIS”没有访问 temp 目录的足够权限.CodeDom 将使用进程正在使用的用户帐户进行 ...

  5. 解决Win10无法安装.Net Framework 3.5,错误代码0x800F081F

    重新安装了一遍Win10,但是不知怎的无法安装.net framework 3.5,即便是下载离线安装包也没法用. 网上有人说需要使用win10的ISO文件,个人感觉太麻烦,在这里分享一个很方便的操作 ...

  6. windows Server 2012/2016 路由和远程访问,PPPOE,ADSL,连接接口时出现一个错误,连接被远程计算机终止

    经过查询资料,是由mprddm.dll的bug引起的. 修改位置: 将je修改为jmp. 查找修改位置,可参考 前面的RasGetPortUserData的调用,或者 后面的 字符串 64位dll可使 ...

  7. Linux下源码编译安装MySQL 5.5.8

    准备工作: 新建用户和用户组 groupadd mysql useradd -g mysql mysql 1:下载: bison-2.4.2.tar.bz2 cmake-2.8.3.tar.gz ma ...

  8. [ML学习笔记] 决策树与随机森林(Decision Tree&Random Forest)

    [ML学习笔记] 决策树与随机森林(Decision Tree&Random Forest) 决策树 决策树算法以树状结构表示数据分类的结果.每个决策点实现一个具有离散输出的测试函数,记为分支 ...

  9. Django商城项目笔记No.8用户部分-注册接口实现

    Django商城项目笔记No.8用户部分-注册接口实现 users的view.py中增加如下代码 class RegisterUserView(CreateAPIView): "" ...

  10. 1.js基础(以通俗易懂的语言解释JavaScript)

    1.JavaScript组成: ECMAScript: 解释器.翻译 -->几乎没有兼容问题 DOM: Document Object Model -->有一些操作不兼容 BOM: Bro ...