dfs序的应用

poj3321 Apple Tree dfs序 + 树状数组

POJ - 3321

题意:

一棵树,每棵树的初始权值为1,现在有两个操作

1. "x" 改变节点x的权值,1变0,0变1

2."x"询问以x为根节点的子树的权值和

题解:

通过dfs序将树上问题转化为区间问题,通过树状数组维护权值和

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 1e5 + 10;
int n, m, h[N],e[N<<1],ne[N<<1],idx;
int L[N],R[N], tot;
int cnt[N];
void add(int a,int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void dfs(int u, int fa)
{
    L[u] = ++tot;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa) continue;
        dfs(j, u);
    }
    R[u] = tot;
}

struct treearray{
    int tr[N], kk;
    int lbt(int x) {
        return x&(-x);
    }
    int ask(int i)
    {
        int sum = 0;
        for (; i; i -= lbt(i)) sum+= tr[i];
        return sum;
    }
    void add(int i, int x)
    {
        for (; i<=kk; i+=lbt(i))
        {
            tr[i] += x;
        }
    }
    void init()
    {
        for (int i = 1; i <= n; i++) cnt[i] = 1,add(i,1);
    }
}t;
int main()
{
    freopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
    cin >> n;
    t.kk = n;
    memset(h, -1, sizeof h);
    for (int i = 1; i < n; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b), add(b,a);
    }
    t.init();
    dfs(1, 0);
    cin >> m;
    while (m--)
    {
        char op[2];
        int x;
        scanf("%s%d", op, &x);
        if (op[0] == 'Q') printf("%d
", t.ask(R[x]) - t.ask(L[x]-1));
        else{
            if (cnt[x])
            {
                t.add(L[x], -1);
                cnt[x] = 0;
            }
            else t.add(L[x], 1), cnt[x] = 1;
        }
    }
}
View Code

A - Counting Offspring

 HDU - 3887

题意:给你一棵树,求每个节点的子节点权值比他小的数的个数

题解:先dfs序,然后用树状数组,从小到大往树状数组对应的位置加1;

C - New Year Tree

 CodeForces - 620E

题意:一棵树,每个节点有一个颜色

两个操作

将以z为根的子树的结点全部更新为颜色X 2,问以z为根的子树的结点的不同颜色数量

题解:dfs序+区间染色需要用, 因为颜色的数量小于60,用Longlong的二进制来表示颜色

#include <iostream>
#include <algorithm>
#include <cstdio>
#include<cstring>
#include<bitset>
using namespace std;
#define scai(x) scanf("%lld", &x);
#define scaii(x, y) scanf("%lld%lld", &x, &y);
#define ll long long
#define int ll
#define re read()
inline int read(){char tempt = getchar();int x = 0, f = 0;while (tempt < '0' || tempt > '9')f |= tempt == '-', tempt = getchar();while (tempt >= '0' && tempt <= '9')x = x * 10 + tempt - '0', tempt = getchar();return f ? -x : x;}
const int N = 4e5 + 10;
int a[N];
int L[N], R[N];
int h[N], ne[N << 1], idx, e[N << 1];
int d[N];
int now;
struct node
{
    int l, r;
    long long color;
    int lazy;
} tr[N << 2];
int f(long long x)
{
    bitset<70> a(x);
    return a.count();
}
void pushdown(int u)
{
    if (tr[u].lazy!=-1)
    {
        tr[u<<1].color = (1ll<<tr[u].lazy);
        tr[u<<1|1].color = (1ll<<tr[u].lazy);
        tr[u<<1].lazy = tr[u].lazy;
        tr[u<<1|1].lazy = tr[u].lazy;
        tr[u].lazy = -1;
    }
}
void pushup(int u)
{
    tr[u].color = (tr[u<<1].color | tr[u<<1|1].color);
}
void add(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}
void dfs(int u, int fa)
{
    L[u] = ++now;
    d[now] = u;
    // cout << L[u] << " ";
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa)
            continue;
        dfs(j, u);
    }
    R[u] = now;
}


void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = {l, l, 1ll<<a[d[l]], -1};

        // cout << l << " " << tr[u].color << endl;
        return;
    }
    else
    {
        tr[u] = {l, r, 0ll, -1};
        int mid = l + r >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

ll query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        return tr[u].color;
    }
    else{
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        ll v = 0ll;
        if (l <= mid) v |= query(u<<1, l, r);
        if (r > mid) v |= query(u<<1|1, l, r);
        pushup(u);
        return v;
    }
}

void modify(int u, int l, int r, int c)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].lazy = c;
        tr[u].color = (1ll<<c);
        // pushup(u);
    }
    else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u<<1, l, r, c);
        if (r > mid) modify(u<<1|1, l, r, c);
        pushup(u);
    }
}

signed main()
{
    freopen("in.txt", "r", stdin);freopen("out.txt","w", stdout);
    int n, m;
    memset(h, -1, sizeof h);
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        a[i] = re;
    }
    for (int i = 1; i < n; i++)
    {
        int a, b;
        a = re, b = re;
        add(a, b), add(b, a);
    }
    dfs(1, 0);
    build(1, 1, n);

    while (m--)
    {
        int op, z;
        op = re, z = re;
        if (op == 1)
        {
            int x;
            scai(x);
            modify(1, L[z], R[z], x);
        }
        else
        {
            printf("%lld
", f(query(1, L[z], R[z])));
        }
    }
}
View Code

A Party for You Started

题意:每次给树上一个节点增加一个值,询问某个节点到根节点的权值和

方法一:

题解:

还是先dfs序将数展开,用线段数为何每个节点到根节点的和,如果一个节点的值加上一个k,相当于以这个节点为根节点的子树的所有节点加上一个k,这样就转化为线段树区间染色和单点查询问题

 方法二:

题解:
这题还可以用欧拉序+树状数组维护前缀和

欧拉序进的地方加v,出的地方减v每次询问求进的地方的前缀和

#include <iostream>
#include <algorithm>
#include <cstdio>
#include<cstring>
#include<bitset>
using namespace std;
#define scai(x) scanf("%lld", &x);
#define scaii(x, y) scanf("%lld%lld", &x, &y);
#define ll long long
#define int ll
#define re read()
inline int read(){char tempt = getchar();int x = 0, f = 0;while (tempt < '0' || tempt > '9')f |= tempt == '-', tempt = getchar();while (tempt >= '0' && tempt <= '9')x = x * 10 + tempt - '0', tempt = getchar();return f ? -x : x;}
 #define STDIN freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);//************************************
const int N = 4e4 + 10;

int L[N<<2], R[N<<2];
int euler[N<<2],cnt;
int h[N<<2], ne[N<<2], e[N<<2], idx;
int n, m;
void add(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}
void dfs(int u, int fa)
{
    euler[++cnt] = u;
    L[u] = cnt;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa) continue;
        dfs(j, u);
    }
    euler[++cnt] = u;
    R[u] = cnt;
}
struct treearray{
    int kk, tr[N];
    int lbt(int x)
    {
        return x & (-x);
    }

    void add(int i, int v)
    {
        for (; i <= kk; i += lbt(i)) tr[i] += v;
    }
    int ask(int i)
    {
        int sum = 0;
        for (; i; i -= lbt(i)) sum += tr[i]; return sum;
    }
    
}t;
signed main()
{
    STDIN
    memset(h, -1, sizeof h);
    scaii(n, m);
    for (int i = 1; i <= n; i++)
    {
        int t;
        scai(t);
        add(t, i), add(i, t);
    }
    dfs(0,-1);
    t.kk = cnt;
    for (int i = 1; i <= m; i++)
    {
        int u, x, v;
        scaii(u, x);
        scai(v);
        printf("%lld
", t.ask(L[v]));
        t.add(L[u],x);
        t.add(R[u],-x);
    }

}
View Code

方法二

#include <iostream>
#include <algorithm>
#include <cstdio>
#include<cstring>
#include<bitset>
using namespace std;
#define scai(x) scanf("%lld", &x);
#define scaii(x, y) scanf("%lld%lld", &x, &y);
#define ll long long
#define int ll
#define re read()
inline int read(){char tempt = getchar();int x = 0, f = 0;while (tempt < '0' || tempt > '9')f |= tempt == '-', tempt = getchar();while (tempt >= '0' && tempt <= '9')x = x * 10 + tempt - '0', tempt = getchar();return f ? -x : x;}
 #define STDIN freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);//************************************
const int N = 2e4 + 10;

int e[N<<1], ne[N<<1], idx, h[N];

int n,m,now;
int L[N], R[N], d[N];

struct node{
    int l, r,sum;
    int lazy;
}tr[N<<4];
void add(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}

void dfs(int u, int fa)
{
    L[u] = ++now;
    d[now] = u;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa) continue;
        dfs(j, u);
    }
    R[u] = now;
}

void pushdown(int u)
{
    if (tr[u].lazy > 0)
    {
        tr[u<<1].lazy += tr[u].lazy;
        tr[u<<1|1].lazy += tr[u].lazy;
        tr[u<<1].sum += tr[u].lazy;
        tr[u<<1|1].sum += tr[u].lazy;
        tr[u].lazy = 0;
    }
}
void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = {l, l, 0,0};
    }
    else {
        tr[u] = {l, r, 0,0};
        int mid = l + r >> 1;
        build(u<<1, l, mid), build(u<<1|1, mid + 1, r);
    }
}

void modify(int u, int l, int r, int v)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].sum+=v;
        tr[u].lazy += v;
    }
    else{
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u<<1, l, r, v);
        if (r > mid) modify(u<<1|1, l, r, v);
    }
}

int query(int u, int x)
{
    if (tr[u].l == x && tr[u].r == x)
    {
        return tr[u].sum;
    }
    else{
        pushdown(u);
        int mid = tr[u].l+tr[u].r >> 1;
        int v = 0;
        if (x <= mid) return query(u<<1, x);
        if (x > mid) return query(u<<1|1, x);
    }
}
signed main()
{
    STDIN
    memset(h, -1, sizeof h);
    scaii(n, m);
    for (int i = 1; i <= n; i++)
    {
        int t;
        scai(t);
        add(t, i), add(i, t);
    }
    dfs(0,-1);
    build(1,1,n+1);
    for (int i = 1; i <= m; i++)
    {
        int l, v, x;
        scaii(l, v);
        scai(x);
        printf("%lld
", query(1, L[x]));
        modify(1, L[l], R[l], v);
    }
}
View Code
原文地址:https://www.cnblogs.com/hulian425/p/13667302.html