树相关板子整理

换根树链剖分

ll son[maxn], siz[maxn], fa[maxn], top[maxn], dep[maxn], val[maxn];
ll in[maxn], out[maxn], tot, pos[maxn];
ll root;
ll sum[maxn << 2], add[maxn << 2];
ll n, m;

struct Edge
{
    
    
    ll u, v, next;
} edges[maxn];

ll heads[maxn], tot1;

void addEdge(ll u, ll v)
{
    
    
    edges[++tot1].next = heads[u];
    edges[tot1].u = u;
    edges[tot1].v = v;
    heads[u] = tot1;
}

void dfs1(ll u)
{
    
    
    siz[u] = 1;
    for (ll i = heads[u]; i; i = edges[i].next)
    {
    
    
        ll v = edges[i].v;
        if (v == fa[u])
            continue;
        fa[v] = u;
        dep[v] = dep[u] + 1;
        dfs1(v);
        siz[u] += siz[v];
        if (siz[v] > siz[son[u]])
            son[u] = v;
    }
}

void dfs2(ll u)
{
    
    
    in[u] = ++tot;
    pos[tot] = u;
    if (son[u])
    {
    
    
        top[son[u]] = top[u];
        dfs2(son[u]);
    }
    for (ll i = heads[u]; i; i = edges[i].next)
    {
    
    
        ll v = edges[i].v;
        if (v == fa[u] || v == son[u])
            continue;
        top[v] = v;
        dfs2(v);
    }
    out[u] = tot;
}

ll LCA(ll u, ll v)
{
    
    
    while (top[u] != top[v])
    {
    
    
        if (dep[top[u]] > dep[top[v]])
            swap(u, v);
        v = fa[top[v]];
    }
    return dep[u] > dep[v] ? v : u;
}

void pushup(ll k)
{
    
    
    sum[k] = sum[k << 1] + sum[k << 1 | 1];
}

void pushnow(ll k, ll l, ll r, ll val)
{
    
    
    add[k] += val;
    sum[k] += 1ll * (r - l + 1) * val;
}

void pushdown(ll k, ll l, ll r)
{
    
    
    if (add[k])
    {
    
    
        ll mid = (l + r) >> 1;
        pushnow(k << 1, l, mid, add[k]);
        pushnow(k << 1 | 1, mid + 1, r, add[k]);
        add[k] = 0;
    }
}

void build(ll k, ll l, ll r)
{
    
    
    if (l == r)
    {
    
    
        sum[k] = val[pos[l]];
        return;
    }
    ll mid = (l + r) >> 1;
    build(k << 1, l, mid);
    build(k << 1 | 1, mid + 1, r);
    pushup(k);
}

ll query(ll k, ll l, ll r, ll ql, ll qr)
{
    
    
    if (ql <= l && r <= qr)
        return sum[k];
    pushdown(k, l, r);
    ll mid = (l + r) >> 1;
    if (qr <= mid)
        return query(k << 1, l, mid, ql, qr);
    if (mid < ql)
        return query(k << 1 | 1, mid + 1, r, ql, qr);
    return query(k << 1, l, mid, ql, qr) + query(k << 1 | 1, mid + 1, r, ql, qr);
}

void modify(ll k, ll l, ll r, ll ql, ll qr, ll val)
{
    
    
    if (ql <= l && r <= qr)
        return pushnow(k, l, r, val);
    pushdown(k, l, r);
    ll mid = (l + r) >> 1;
    if (ql <= mid)
        modify(k << 1, l, mid, ql, qr, val);
    if (qr > mid)
        modify(k << 1 | 1, mid + 1, r, ql, qr, val);
    pushup(k);
}

void addpath(ll u, ll v, ll val)
{
    
    
    while (top[u] != top[v])
    {
    
    
        if (dep[top[v]] > dep[top[u]])
            swap(u, v);
        modify(1, 1, n, in[top[u]], in[u], val);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v])
        swap(u, v);
    modify(1, 1, n, in[v], in[u], val);
}

ll querypath(ll u, ll v)
{
    
    
    ll res = 0;
    while (top[u] != top[v])
    {
    
    
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);
        res += query(1, 1, n, in[top[u]], in[u]);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v])
        swap(u, v);
    return res + query(1, 1, n, in[v], in[u]);
}

ll find(ll u, ll v)
{
    
    
    while (top[u] != top[v])
    {
    
    
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);
        if (fa[top[u]] == v)
            return top[u];
        u = fa[top[u]];
    }
    if (dep[u] < dep[v])
        swap(u, v);
    return son[v];
}

void addsubtree(ll u, ll val)
{
    
    
    if (u == root)
        return modify(1, 1, n, 1, n, val);
    ll lca = LCA(u, root);
    if (lca != u)
        return modify(1, 1, n, in[u], out[u], val);
    ll son = find(u, root);
    modify(1, 1, n, 1, n, val);
    modify(1, 1, n, in[son], out[son], -val);
}

ll querysubtree(ll u)
{
    
    
    if (u == root)
        return query(1, 1, n, 1, n);
    ll lca = LCA(u, root);
    if (lca != u)
        return query(1, 1, n, in[u], out[u]);
    ll son = find(u, root);
    return query(1, 1, n, 1, n) - query(1, 1, n, in[son], out[son]);
}

signed main()
{
    
    
    scanf("%lld%lld", &n, &m);
    for (ll i = 1; i <= n; i++)
    {
    
    
        scanf("%lld", &val[i]);
    }
    for (ll i = 2; i <= n; i++)
    {
    
    
        ll u, v;
        scanf("%lld%lld", &u, &v);
        addEdge(u, v);
        addEdge(v, u);
    }
    root = 1;
    dfs1(root);
    top[1] = 1;
    dfs2(1);
    build(1, 1, n);
    while (m--)
    {
    
    
        ll op;
        scanf("%lld", &op);
        if (op == 1)//换根
        {
    
    
            ll u;
            scanf("%lld", &u);
            root = u;
        }
        else if (op == 2)//找换根LCA更改子树
        {
    
    
            ll u, v;
            scanf("%lld%lld", &u, &v);
            ll val;
            scanf("%lld", &val);
            ll zu1=LCA(u, root);
            ll zu2=LCA(v, root);
            ll zu;
            if(zu1!=zu2)
            {
    
    
                if(dep[zu1]>dep[zu2])
                {
    
    
                    zu=zu1;
                }
                else
                {
    
    
                    zu=zu2;
                }
            }
            else
            {
    
    
                zu=LCA(u,v);
            }
            // printf("zu:%lld\n", zu);
            addsubtree(zu, val);

        }
        else//查询子树和
        {
    
    
            ll u;
            scanf("%lld", &u);
            printf("%lld\n", querysubtree(u));
        }
    }
    return 0;
}

可持久化trie树

struct Trie
{
    
    
    ll tr[maxn * 32][2], cnt[maxn * 32], idx;
    void insert(ll &u, ll p, ll val, ll len)
    {
    
    
        u = ++idx;
        ll q = u;
        for (ll i = len; i >= 0; i--)
        {
    
    
            cnt[q] = cnt[p] + 1;
            ll v = (val >> i & 1);
            tr[q][v ^ 1] = tr[p][v ^ 1];
            tr[q][v] = ++idx;
            q = tr[q][v], p = tr[p][v];
        }
        cnt[q] = cnt[p] + 1;
    }
    ll query(ll p, ll q, ll val, ll k, ll len) //从p到q异或上val的第k小的值
    {
    
    
        ll res = 0;
        for (ll i = len; i >= 0; i--)
        {
    
    
            ll v = (val >> i & 1);
            ll num = cnt[tr[q][v ^ 1]] - cnt[tr[p][v ^ 1]];
            if (num < k)
                k -= num, p = tr[p][v], q = tr[q][v];
            else
                res += (1 << i), p = tr[p][v ^ 1], q = tr[q][v ^ 1];
        }
        return res;
    }
} trie;

trie.insert(root[x], root[x-1], arr[x], 31);
printf("%lld\n", trie.query(root[l-1], root[r], val, k, 31));

树上启发式合并


void go(ll u,ll fa,ll type)
{
    
    
    cnt[arr[u]]+=type;
    if(type==1&&cnt[arr[u]]==1) ans++;
    if(type==-1&&cnt[arr[u]]==0) ans--;
    for(auto v:to[u])
    {
    
    
        if(v==fa) continue;
        go(v,u,type);
    }
}

void dfs3(ll u, ll fa, ll del)//del是否需要删除
{
    
    
    for(auto v:to[u])
    {
    
    
        if(v==fa||v==son[u]) continue;
        dfs3(v,u,1);
    }
    if(son[u]!=0)
    {
    
    
        dfs3(son[u],u,0);
    }
    cnt[arr[u]]++; if(cnt[arr[u]]==1) ans++;
    for(auto v:to[u])
    {
    
    
        if(v==fa||v==son[u]) continue;
        go(v,u,1);
    }
    dp[u]=ans;
    if(del)
    {
    
    
        go(u,fa,-1);
    }
}

树链剖分

ll n, m, r, p, cnt;
ll arr[maxn], dep[maxn], fa[maxn], siz[maxn];
ll son[maxn], id[maxn], w[maxn], top[maxn], sum[maxn << 2], add[maxn << 2];

vector<ll> to[maxn];

void dfs1(ll now, ll fath)
{
    
    
    // printf("*1\n");
    dep[now] = dep[fath] + 1;
    fa[now] = fath;
    siz[now] = 1;
    ll maxson = -1;
    for (auto v : to[now])
    {
    
    
        if (v == fath)
            continue;
        dfs1(v, now);
        siz[now] += siz[v];
        if (siz[v] > maxson)
        {
    
    
            son[now] = v;
            maxson = siz[v];
        }
    }
}

void dfs2(ll now, ll topf)
{
    
    
    id[now] = ++cnt;
    w[cnt] = arr[now];
    top[now] = topf;
    if (!son[now])
    {
    
    
        return;
    }
    dfs2(son[now], topf);
    for (auto v : to[now])
    {
    
    
        if (v == fa[now] || v == son[now])
        {
    
    
            continue;
        }
        dfs2(v, v);
    }
}

void pushUp(ll rt)
{
    
    
    sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]) % p;
}

void pushDown(ll rt, ll ln, ll rn)
{
    
    
    if (add[rt])
    {
    
    
        sum[rt << 1] = (sum[rt << 1] + add[rt]*ln) % p;
        sum[rt << 1 | 1] = (sum[rt << 1 | 1] + add[rt]*rn) % p;
        add[rt << 1] = (add[rt << 1] + add[rt]) % p;
        add[rt << 1 | 1] = (add[rt << 1 | 1] + add[rt]) % p;
        add[rt] = 0;
    }
}

void build(ll l, ll r, ll rt)
{
    
    
    if (l == r)
    {
    
    
        sum[rt] = w[l] % p;
        return;
    }
    ll m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushUp(rt);
}

void update(ll L, ll R, ll c, ll l, ll r, ll rt)
{
    
    
    if (L <= l && r <= R)
    {
    
    
        sum[rt] = (sum[rt] + (r - l + 1) * c) % p;
        add[rt] = (add[rt] + c) % p;
        return;
    }
    ll m = (l + r) >> 1;
    pushDown(rt, m - l + 1, r - m);
    if (m >= L)
        update(L, R, c, lson);
    if (m < R)
        update(L, R, c, rson);
    pushUp(rt);
}

ll query(ll L, ll R, ll l, ll r, ll rt)
{
    
    
    if (L <= l && r <= R)
    {
    
    
        return sum[rt];
    }
    ll m = (l + r) >> 1;
    pushDown(rt, m - l + 1, r - m);
    ll ans = 0;
    if (m >= L)
        ans += query(L, R, lson);
    if (m < R)
        ans += query(L, R, rson);
    return ans%p;
}

void upd(ll x, ll y, ll c)
{
    
    
    c %= p;
    while (top[x] != top[y])
    {
    
    
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        update(id[top[x]], id[x], c, 1, n,1);
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x, y);
    update(id[x], id[y], c, 1, n,1);
    //update(id[x] + 1, id[y], c, 1, n);//边权转化为点权,避开LCA

}

ll qry(ll x, ll y)
{
    
    
    ll ans = 0;
    while (top[x] != top[y])
    {
    
    
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        ans += query(id[top[x]], id[x], 1, n,1);
        ans %= p;
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        swap(x, y);
    ans += query(id[x], id[y], 1, n,1);
    ans %= p;
    return ans;
}

void updSon(ll x, ll c)
{
    
    
    update(id[x], id[x] + siz[x] - 1, c, 1, n,1);
}

ll qrySon(ll x)
{
    
    
    return query(id[x], id[x] + siz[x] - 1, 1, n,1);
}

int main()
{
    
    
    // DEBUG;
    scanf("%lld%lld%lld%lld", &n, &m, &r, &p);
    for (ll i = 1; i <= n; i++)
    {
    
    
        scanf("%lld", &arr[i]);
    }
    for (ll i = 1; i <= n - 1; i++)
    {
    
    
        ll u, v;
        scanf("%lld%lld", &u, &v);
        to[u].push_back(v);
        to[v].push_back(u);
    }
    // printf("*1\n");
    dfs1(r, 0);
    // printf("*1\n");
    dfs2(r, r);
    build(1, n,1);
    for (ll i = 1; i <= m; i++)
    {
    
    
        ll op;
        scanf("%lld", &op);
        if (op == 1)
        {
    
    
            ll x, y, c;
            scanf("%lld%lld%lld", &x, &y, &c);
            upd(x, y, c);
        }
        else if (op == 2)
        {
    
    
            ll x, y;
            scanf("%lld%lld", &x, &y);
            printf("%lld\n", qry(x, y)%p);
        }
        else if (op == 3)
        {
    
    
            ll x, c;
            scanf("%lld%lld", &x, &c);
            updSon(x, c);
        }
        else if (op == 4)
        {
    
    
            ll x;
            scanf("%lld", &x);
            printf("%lld\n", qrySon(x)%p);
        }
    }
}

二叉搜索树

const ll maxn = 1e3 + 10;
typedef struct Node *BinTree;
ll n, s = 0, t = 0, k = 0;
ll a[maxn], b[maxn], c[maxn];

struct Node
{
    
    
    ll data;
    BinTree left, right;
};

//建立二叉搜索树 
BinTree CreatTree(BinTree BST, ll x)
{
    
    
    if (!BST)
    {
    
    
        BST = new Node;
        BST->data = x;
        BST->left = BST->right = 0;
    }
    else
    {
    
    
        if (x < BST->data)
        {
    
    
            BST->left = CreatTree(BST->left, x);
        }
        else
        {
    
    
            BST->right = CreatTree(BST->right, x);
        }
    }
    return BST;
}

//先序遍历 
void PreorderTraversal(BinTree BST)
{
    
    
    if (BST)
    {
    
    
        b[s++] = BST->data;
        PreorderTraversal(BST->left);
        PreorderTraversal(BST->right);
    }
}

//镜面先序输出 
void MirrorPreorderTraversal(BinTree BST)
{
    
    
    if (BST)
    {
    
    
        c[t++] = BST->data;
        MirrorPreorderTraversal(BST->right);
        MirrorPreorderTraversal(BST->left);
    }
}

//后序遍历 
ll k1 = 0;
void PostorderTraversal(BinTree BST)
{
    
    
    if (BST)
    {
    
    
        PostorderTraversal(BST->left);
        PostorderTraversal(BST->right);
        if (k1)
            cout << " ";
        cout << BST->data;
        k1 = 1;
    }
}

//镜面后序遍历 
ll k2 = 0;
void MirrorPostorderTraversal(BinTree BST)
{
    
    
    if (BST)
    {
    
    
        MirrorPostorderTraversal(BST->right);
        MirrorPostorderTraversal(BST->left);
        if (k2)
            cout << " ";
        cout << BST->data;
        k2 = 1;
    }
}

int main()
{
    
    
    // DEBUG;
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    BinTree BST;
    BST = NULL;
    cin >> n;
    for (ll i = 0; i < n; i++)
    {
    
    
        cin >> a[i];
        BST = CreatTree(BST, a[i]);
    }
    PreorderTraversal(BST);
    MirrorPreorderTraversal(BST);
    ll flag1 = 1, flag2 = 1;
    for (ll i = 0; i < n; i++)
    {
    
    
        if (a[i] != b[i])
        {
    
    
            flag1 = 0;
            break;
        }
    }
    for (ll i = 0; i < n; i++)
    {
    
    
        if (a[i] != c[i])
        {
    
    
            flag2 = 0;
            break;
        }
    }
    if (flag1 == 0 && flag2 == 0)
    {
    
    
        cout << "NO" << endl;
    }
    else
    {
    
    
        cout << "YES" << endl;
        if (flag1)
        {
    
    
            PostorderTraversal(BST);
        }
        else
        {
    
    
            MirrorPostorderTraversal(BST);
        }
    }
    return 0;
}

二叉树的建立,翻转即层次输出

const ll maxn = 30 + 10;

struct Node
{
    
    
    ll data;
    Tree left, right;
};

ll n;
ll fir[maxn], mid[maxn];

Tree creat(ll n, ll *fir, ll *mid)//由前序,中序建树
{
    
    
    if (n == 0)
        return 0;
    Tree tree = new Node;
    tree->data = fir[0];
    tree->left = tree->right = NULL;
    ll i = 0;
    while (mid[i] != fir[0])
        i++;
    tree->left = creat(i, fir + 1, mid);
    tree->right = creat(n - i - 1, fir + i + 1, mid + i + 1);
    return tree;
}

Tree fanzhuan(Tree tree)//反转树
{
    
    
    Tree t;
    if (tree)
    {
    
    
        if (tree->left || tree->right)
        {
    
    
            t = tree->left;
            tree->left = tree->right;
            tree->right = t;
        }
        fanzhuan(tree->left);
        fanzhuan(tree->right);
    }
    return tree;
}

void order(ll n,Tree tree)//层次输出
{
    
    
    if(!n) return;
    queue<Tree>que;
    que.push(tree);
    ll len=0;
    while(!que.empty())
    {
    
    
        Tree temp=que.front();
        que.pop();
        if(!len) 
        {
    
    
            cout<<temp->data;
            len++;
        }
        else cout<<" "<<temp->data;
        if(temp->left)
        {
    
    
            que.push(temp->left);
        }
        if(temp->right)
        {
    
    
            que.push(temp->right);
        }
    }
}

int main()
{
    
    
    // DEBUG;
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (ll i = 0; i < n; i++)
    {
    
    
        cin >> mid[i];
    }
    for (ll i = 0; i < n; i++)
    {
    
    
        cin >> fir[i];
    }
    Tree tree = creat(n, fir, mid);
    tree=fanzhuan(tree);
    order(n,tree);
    return 0;
}

根据子树个数顺序中序排列建树

//设tree[i][0] 为第i个节点的左节点编号
//设tree[i][1] 为第i个节点的右节点编号

void dfs(int root){
    
    //root表示几号节点
    tot++;//表示总共访问了几个节点。
    if (s[root]=='0') return;//叶子节点退出
    if (s[root]=='1') {
    
    
        tree[root][0]=root+1;//下一个访问的节点的编号一定是这个节点编号+1
        dfs(root+1);//向下搜
    }
    if (s[root]=='2') {
    
    
        tree[root][0]=root+1;
        dfs(root+1);
        tree[root][1]=tot+1;//右节点一定是总共访问的编号+1
        dfs(tot+1);
    }
}

猜你喜欢

转载自blog.csdn.net/m0_51270992/article/details/115187566
今日推荐