zoukankan      html  css  js  c++  java
  • [洛谷P1501][国家集训队]Tree II(LCT)

    题目链接

    做了几道LCT,发现大多涉及到修改树上路径。本题也一样,4个操作中其实主要麻烦的就是加C和乘C,只需要维护区间和的同时记录加法和乘法的lazy标记,并且在pushdown的时候先乘再加即可。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const unsigned int maxn = 120010;
      5 const unsigned int mod = 51061;
      6 unsigned int fa[maxn], ch[maxn][2], siz[maxn], val[maxn], sum[maxn], lr[maxn], lm[maxn], la[maxn], st[maxn];//父亲节点,左右儿子节点,当前子数节点个数,当前值,lr标记,辅助数组。
      7 inline bool isroot(unsigned int x) {//判断x是否为所在splay的根
      8     return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
      9 }
     10 inline void pushup(unsigned int x) {
     11     sum[x] = (sum[ch[x][0]] + sum[ch[x][1]] + val[x]) % mod;
     12     siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
     13 }
     14 inline void pusha(unsigned int x, unsigned int c) {
     15     sum[x] = (sum[x] + c * siz[x]) % mod;
     16     val[x] = (val[x] + c) % mod;
     17     la[x] = (la[x] + c) % mod;
     18 }
     19 inline void pushm(unsigned int x, unsigned int c) {
     20     sum[x] = sum[x] * c%mod;
     21     val[x] = val[x] * c%mod;
     22     lm[x] = lm[x] * c%mod;
     23     la[x] = la[x] * c%mod;
     24 }
     25 inline void pushr(unsigned int x) {
     26     swap(ch[x][0], ch[x][1]);
     27     lr[x] ^= 1;
     28 }
     29 inline void pushdown(unsigned int x) {
     30     if (lm[x] != 1) {
     31         if (ch[x][0])pushm(ch[x][0], lm[x]);
     32         if (ch[x][1])pushm(ch[x][1], lm[x]);
     33         lm[x] = 1;
     34     }
     35     if (la[x]) {
     36         if (ch[x][0])pusha(ch[x][0], la[x]);
     37         if (ch[x][1])pusha(ch[x][1], la[x]);
     38         la[x] = 0;
     39     }
     40     if (lr[x]) {
     41         if (ch[x][0])pushr(ch[x][0]);
     42         if (ch[x][1])pushr(ch[x][1]);
     43         lr[x] = 0;
     44     }
     45 }
     46 inline void rotate(unsigned int x) {
     47     unsigned int y = fa[x], z = fa[y];
     48     unsigned int k = ch[y][1] == x;
     49     if (!isroot(y))
     50         ch[z][ch[z][1] == y] = x;
     51     fa[x] = z; ch[y][k] = ch[x][k ^ 1]; fa[ch[x][k ^ 1]] = y;
     52     ch[x][k ^ 1] = y; fa[y] = x;
     53     pushup(y);
     54     pushup(x);
     55 }
     56 inline void splay(unsigned int x) {
     57     unsigned int f = x, len = 0;
     58     st[++len] = f;
     59     while (!isroot(f))st[++len] = f = fa[f];
     60     while (len)pushdown(st[len--]);
     61     while (!isroot(x)) {
     62         unsigned int y = fa[x];
     63         unsigned int z = fa[y];
     64         if (!isroot(y))
     65             rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y);
     66         rotate(x);
     67     }
     68     pushup(x);
     69 }
     70 inline void access(unsigned int x) {//打通根节点到x的实链
     71     for (unsigned int y = 0; x; x = fa[y = x])
     72         splay(x), ch[x][1] = y, pushup(x);
     73 }
     74 inline void makeroot(unsigned int x) {//将x变为原树的根
     75     access(x); splay(x); pushr(x);
     76 }
     77 unsigned int Findroot(unsigned int x) {//找根节点
     78     access(x), splay(x);
     79     while (ch[x][0])
     80         pushdown(x), x = ch[x][0];
     81     splay(x);
     82     return x;
     83 }
     84 inline void split(unsigned int x, unsigned int y) {//将x到y路径变为play
     85     makeroot(x); access(y); splay(y);
     86 }
     87 inline void Link(unsigned int x, unsigned int y) {//合法连边
     88     makeroot(x); fa[x] = y;
     89 }
     90 inline void cut(unsigned int x, unsigned int y) {//合法断边
     91     split(x, y); fa[x] = ch[y][0] = 0; pushup(y);
     92 }
     93 int main() {
     94     unsigned int n, q;
     95     unsigned int x, y, u, v;
     96     scanf("%d%d", &n, &q);
     97     for (unsigned int i = 1; i <= n; i++)val[i] = siz[i] = lm[i] = 1;
     98     for (unsigned int i = 1; i < n; i++) {
     99         scanf("%d%d", &x, &y);
    100         Link(x, y);
    101     }
    102     while (q--) {
    103         char s[2];
    104         scanf("%s", s);
    105         if (s[0] == '+') {
    106             scanf("%d%d%d", &x, &y, &u);
    107             split(x, y);
    108             pusha(y, u);
    109         }
    110         else if (s[0] == '-') {
    111             scanf("%d%d%d%d", &x, &y, &u, &v);
    112             cut(x, y);
    113             Link(u, v);
    114         }
    115         else if (s[0] == '*') {
    116             scanf("%d%d%d", &x, &y, &u);
    117             split(x, y);
    118             pushm(y, u);
    119         }
    120         else if (s[0] == '/') {
    121             scanf("%d%d", &x, &y);
    122             split(x, y);
    123             printf("%d
    ", sum[y]);
    124         }
    125     }
    126 }
  • 相关阅读:
    剑指offer_24:二叉树中和为某一值的路径
    剑指offer_23:二叉搜索树的后序遍历序列
    Java基础类型大小
    旋转数组
    剑指offer_22:从上往下打印二叉树
    剑指offer_21:栈的压入、弹出序列
    剑指offer_20:包含min函数的栈
    剑指offer_19:顺时针打印矩阵
    剑指offer_18:二叉树的镜像
    redis jedis源码
  • 原文地址:https://www.cnblogs.com/sainsist/p/11414906.html
Copyright © 2011-2022 走看看