• 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
  • 相关阅读:
    chrome 的 css hack
    WebService报用户名密码错误
    银行系统数据加密方法
    (转)让插入到 innerHTML 中的 script 跑起来
    JSP导出Excel
    简单使用JDOM解析XML 完整版 转
    IO流读取文件
    JSP下载服务器文件
    (转JAVAEYE)System类方法大全
    list 排序
  • 原文地址:https://www.cnblogs.com/hulian425/p/13667302.html
Copyright © 2020-2023  润新知