zoukankan      html  css  js  c++  java
  • LCT模板

    题目链接:

     
    lct一开始本没有splay 是在access的时候现建的 所以一开始每个点仅存了fa
     
      1 #include <cstdio>
      2 #include <algorithm>
      3 using namespace std;
      4 const int N = 3e5 + 5;
      5 int n, m;
      6 struct Splay{
      7     int ch[2], fa, w, rev, sum;
      8 }spl[N]; 
      9 int s[N];
     10 
     11 inline bool get(int x){
     12     return x == spl[spl[x].fa].ch[1];
     13 }
     14 
     15 inline void update(int x){
     16     spl[x].sum = spl[x].w ^ spl[spl[x].ch[0]].sum ^ spl[spl[x].ch[1]].sum;
     17 }//统计抑或和 
     18 
     19 inline void pushdown(int x){
     20     if(!spl[x].rev) return ;
     21     int &ls = spl[x].ch[0], &rs = spl[x].ch[1];
     22     swap(ls, rs);
     23     spl[ls].rev ^= 1;
     24     spl[rs].rev ^= 1;
     25     spl[x].rev ^= 1;
     26 }
     27 
     28 inline bool is_root(int x){
     29     return spl[spl[x].fa].ch[0] != x && spl[spl[x].fa].ch[1] != x; 
     30 }
     31 //注意这里不只有一颗splay 所以根节点不一定是0 
     32  
     33 inline void rotate(int x){
     34     int y = spl[x].fa, z = spl[y].fa;
     35     bool k = get(x);
     36     if(!is_root(y)) spl[z].ch[get(y)] = x;
     37     spl[x].fa = z;
     38     spl[spl[x].ch[k ^ 1]].fa = y; spl[y].ch[k] = spl[x].ch[k ^ 1];
     39     spl[y].fa = x; spl[x].ch[k ^ 1] = y;
     40     update(y); update(x);
     42 }
    //日常rotate
    43 44 void splay(int x){ 45 int top = 0; 46 s[++top] = x; 47 for(int i = x; !is_root(i); i = spl[i].fa) 48 s[++top] = spl[i].fa; 49 while(top > 0) 50 pushdown(s[top--]); 51 for(int f; !is_root(x); rotate(x)) 52 if(!is_root(f = spl[x].fa)) 53 rotate(get(x) == get(f) ? f : x); 54 } 55
    /*
    注意这里除了平时的splay操作还要先把翻转标记下推
    */ 56 void access(int x){ 57 for(int i = 0; x; i = x, x = spl[x].fa){ 58 splay(x); 59 spl[x].ch[1] = i; 60 update(x); 61 } 62 }
    /*
    打通一条从根到x的路径 并为这条路径建上splay
    */
    63 64 void evert(int x){ 65 access(x); 66 splay(x); 67 spl[x].rev ^= 1; 68 }
    /*
    将x变成原树树根
    */
    69 70 int find(int x){ 71 access(x); 72 splay(x); 73 while(spl[x].ch[0]) 74 x = spl[x].ch[0]; 75 return x; 76 }
    /*
    找到原树树根
    */
    77 78 void link(int x, int y){ 79 evert(x); 80 spl[x].fa = y; 81 }
    /*
    连一条x y之间的边
    */
    82 83 void cut(int x, int y){ 84 evert(x); 85 access(y); 86 splay(y); 87 if(spl[x].ch[1] || spl[x].fa != y || spl[y].ch[get(x) ^ 1]) return ; 89 spl[y].ch[0] = spl[x].fa = 0; 90 }
    /*
    切断x y之间的边(当然前提是它们之间有边
    把x转为原树树根
    打通到y的道路
    若x y间有边 现在这个小splay长成这个样子

    所以判断一下就好了……


    */
    91 92 void change(int x, int y){ 93 spl[x].w = y; 94 access(x); 95 splay(x); 96 }
    /*
    修改一个点的信息
    直接修改 然后做相关更新
    */
    97 98 int query(int x, int y){ 99 evert(x); 100 access(y); 101 splay(y); 102 return spl[y].sum; 103 } 104
    /*
    查询路径上的抑或和
    把x转为原树树根
    打通到y的道路
    现在x,y的路径就是整颗splay
    因为当前splay中 x深度最小 y深度最大
    所以 路径上点的信息 的统计 就是 整棵树的统计
    返回 树根统计值 就可以了
    (打了断句…
    */ 105 106 int main(){ 107 scanf("%d%d", &n, &m); 108 for(int i = 1; i <= n; i++) 109 scanf("%d", &spl[i].w); 110 while(m--){ 111 int op, x, y; 112 scanf("%d%d%d", &op, &x, &y); 113 switch(op){ 114 case 0: 115 printf("%d ", query(x, y)); 116 break; 117 case 1: 118 if(find(x) == find(y)) break; 119 link(x, y); 120 break; 121 case 2: 122 if(find(x) != find(y)) break; 123 cut(x, y); 124 break; 125 case 3: 126 change(x, y); 127 break; 128 } 129 } 130 return 0; 131 }

    注意使用手写堆栈 stl会超时

    相关题目 

    裸题…弹飞的连到点n + 1上
  • 相关阅读:
    洛谷P1120信息奥赛一本通1442 小木棍
    洛谷P1378 油滴扩展
    洛谷P1156 垃圾陷阱
    mybatis-Plus 实践篇之逆向工程
    Interceptor的使用及探究
    mysql,oracle,sqlServer 元数据查询
    navicat premium15免费版安装说明(附工具)
    打印日志你真的会吗?
    线程基础知识-必知必会
    空间复杂度&时间复杂度
  • 原文地址:https://www.cnblogs.com/hjmmm/p/9271722.html
Copyright © 2011-2022 走看看