• BZOJ 3223 Tyvj 1729 文艺平衡树


    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=3223

    题目大意:

    维护1-n的数组,每次操作翻转一个区间。

    思路:

    如何找到要操作的区间[l,r]:将当前排名(size)为l-1 +1 的节点转到根,将当前排名为r+2的节点转到根的右子树的根节点,则根的右子树的根节点的左子树为所求区间,直接打标记就可以了。

      1 #include<bits/stdc++.h>
      2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
      3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
      4 #define Min(a, b) ((a) < (b) ? (a) : (b))
      5 #define Mem(a) memset(a, 0, sizeof(a))
      6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
      7 #define MID(l, r) ((l) + ((r) - (l)) / 2)
      8 #define lson ((o)<<1)
      9 #define rson ((o)<<1|1)
     10 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
     11 using namespace std;
     12 inline int read()
     13 {
     14     int x=0,f=1;char ch=getchar();
     15     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     16     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     17     return x*f;
     18 }
     19 
     20 typedef long long ll;
     21 const int maxn = 1000000 + 10;
     22 const int MOD = 1000000007;//const引用更快,宏定义也更快
     23 const int INF = 1e9 + 7;
     24 const double eps = 1e-6;
     25 
     26 int n, m;
     27 struct node
     28 {
     29     int fa;//记录父节点
     30     int ch[2];//ch[0]表示左儿子 ch[1]表示右儿子
     31     int val;//节点权值
     32     int Size;//记录节点子树大小(包括该节点)
     33     int cnt;//记录同样权值的元素个数
     34     int mark;//记录反转区间标记(普通平衡树不用)
     35 }t[maxn];
     36 int root = 0;//根节点
     37 int cnt = 0;//当前节点数目
     38 bool get(int x)//判断一个节点是左节点还是右节点
     39 {
     40     return t[t[x].fa].ch[1] == x;//右节点返回1 左节点返回0
     41 }
     42 void up(int x)//重新统计节点x的size
     43 {
     44     t[x].Size = t[t[x].ch[0]].Size + t[t[x].ch[1]].Size + t[x].cnt;
     45 }
     46 void Rotate(int x)//节点x与父节点旋转
     47 {
     48     int fa = t[x].fa, gfa = t[fa].fa;
     49     int d1 = get(x), d2 = get(fa);//加上d1 d2均表示左儿子
     50     t[fa].ch[d1] = t[x].ch[d1 ^ 1]; t[t[x].ch[d1 ^ 1]].fa = fa;//父节点的左儿子设置成左儿子的右儿子(双向设置)
     51     t[gfa].ch[d2] = x; t[x].fa = gfa;//祖父节点的左儿子设置成父节点的左儿子(双向)
     52     t[fa].fa = x; t[x].ch[d1^1] = fa;//左儿子的右儿子设置成父节点(双向)
     53     up(fa); up(x);
     54 }
     55 void splay(int x, int goal)//x旋转到goal下面
     56 {
     57     while(t[x].fa != goal)
     58     {
     59         int fa = t[x].fa, gfa = t[fa].fa;
     60         int d1 = get(x), d2 = get(fa);
     61         if(gfa != goal)
     62         {
     63             if(d1 == d2)Rotate(fa);//同侧,先旋父节点(双旋)
     64             else Rotate(x);//异侧 直接选
     65         }
     66         Rotate(x);//再向上旋一次
     67     }
     68     if(goal == 0)root = x;
     69 }
     70 void Insert(int val)
     71 {
     72     int node = root, fa = 0;
     73     while(node && t[node].val != val)
     74         fa = node, node = t[node].ch[t[node].val < val];
     75     if(node)t[node].cnt++;//节点存在
     76     else
     77     {
     78         node = ++cnt;
     79         if(fa)t[fa].ch[t[fa].val < val] = node;
     80         t[node].fa = fa;
     81         t[node].Size = t[node].cnt = 1;
     82         t[node].val = val;
     83     }
     84     splay(node, 0);//将新节点旋到根来维护splay的子树
     85 }
     86 
     87 void pushdown(int x)
     88 {
     89     t[t[x].ch[0]].mark ^= 1;
     90     t[t[x].ch[1]].mark ^= 1;
     91     t[x].mark = 0;
     92     swap(t[x].ch[0], t[x].ch[1]);
     93 }
     94 int kth(int k)//查询第k大的数
     95 {
     96     int node = root;
     97     while(1)
     98     {
     99         if(t[node].mark)pushdown(node);
    100         int son = t[node].ch[0];
    101         if(k <= t[son].Size)node = son;
    102         else if(k > t[son].Size + t[node].cnt)
    103         {
    104             k -= t[son].Size + t[node].cnt;
    105             node = t[node].ch[1];
    106         }
    107         else return node;//返回编号 
    108     }
    109 }
    110 void work(int l, int r)//将l-1节点转到根节点 r+1节点转到根节点的右节点 
    111                       //直接标记根节点的右节点的左节点就是区间l-r 
    112 {
    113     int left = kth(l), right = kth(r);
    114     splay(left, 0);
    115     splay(right, left);
    116     t[t[t[root].ch[1]].ch[0]].mark ^= 1;
    117 }
    118 
    119 void output(int x)
    120 {
    121     if(t[x].mark)pushdown(x);
    122     if(t[x].ch[0])output(t[x].ch[0]);
    123     if(t[x].val >= 1 && t[x].val <= n)printf("%d ", t[x].val);
    124     if(t[x].ch[1])output(t[x].ch[1]);
    125 }
    126 
    127 int main()
    128 {
    129     int  x, y;
    130     Insert(INF);
    131     Insert(-INF);
    132     scanf("%d%d", &n, &m);
    133     for(int i = 1; i <= n; i++)Insert(i); 
    134     while(m--)
    135     {
    136         scanf("%d%d", &x, &y);
    137         work(x, y + 2);//由于有负无穷 等价于x-1节点 和 y+1节点 
    138     }
    139     output(root);
    140     puts("");
    141     return 0;
    142 }
  • 相关阅读:
    贴图UV动画
    编辑器开发读取LIGHTMAP的脚本
    一个角色旋转身体在向前行走的代码
    第一周
    《大道至简》读后感
    第二周
    Easyui,好的设计思路
    有关反射
    Easyui表格的行编辑
    冒泡排序
  • 原文地址:https://www.cnblogs.com/fzl194/p/9678076.html
Copyright © 2020-2023  润新知