• (好题)树状数组+离散化+DFS序+离线/莫队 HDOJ 4358 Boring counting


    题目传送门

    题意:给你一棵树,树上的每个节点都有树值,给m个查询,问以每个点u为根的子树下有多少种权值恰好出现k次。

    分析:首先要对权值离散化,然后要将树形转换为线形,配上图:。然后按照右端点从小到大排序,离线操作:将每一个深度的权值分组到相同权值的cnt中,当sz == k时,用树状数组更新+1,表示在该深度已经存在k个相同的权值,如果>k,之前k个-2(-1是恢复原样,再-1是为下次做准备?),然后一个点的子树的答案就是 sum (r) - sum (l-1)。

    当然,区间离线问题用莫队算法是很好做的。

    收获:1. 离散化  2. DFS序,树形变线形  3. 离线操作  4. 莫队算法

    代码(树状数组):

    /************************************************
    * Author        :Running_Time
    * Created Time  :2015/9/10 星期四 19:15:22
    * File Name     :I.cpp
     ************************************************/
    
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <sstream>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <vector>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <list>
    #include <map>
    #include <set>
    #include <bitset>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    
    #define lson l, mid, rt << 1
    #define rson mid + 1, r, rt << 1 | 1
    typedef long long ll;
    const int N = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e9 + 7;
    struct Edge {
        int v, nex;
    }edge[N*2];
    struct Query    {
        int l, r, id;
        Query (int _l = 0, int _r = 0, int _id = 0) : l (_l), r (_r), id (_id) {}
        bool operator < (const Query &x) const  {
            return r < x.r;
        }
    }q[N];
    struct BIT  {
        int c[N];
        void init(void) {
            memset (c, 0, sizeof (c));
        }
        void updata(int i, int x)   {
            while (i < N)   {
                c[i] += x;  i += i & (-i);
            }
        }
        int query(int i)    {
            int ret = 0;
            while (i)   {
                ret += c[i];    i -= i & (-i);
            }
            return ret;
        }
    }bit;
    int head[N], dfn[N], low[N], w[N], p[N], val[N], ans[N];
    vector<int> cnt[N];
    int e, dep;
    
    void init(void) {
        memset (head, -1, sizeof (head));
        e = 0;  dep = 0;
    }
    
    void add_edge(int u, int v) {
        edge[e].v = v;  edge[e].nex = head[u];
        head[u] = e++;
    }
    
    bool cmp(int i, int j)  {
        return w[i] < w[j];
    }
    
    void compress(int n)    {
        for (int i=1; i<=n; ++i)    p[i] = i;
        sort (p+1, p+1+n, cmp);
        int rk = 0, pre = w[p[1]] - 1;
        for (int i=1; i<=n; ++i)    {
            if (pre != w[p[i]]) {
                pre = w[p[i]];
                w[p[i]] = ++rk;
            }
            else    {
                w[p[i]] = rk;
            }
        }
    }
    
    void DFS(int u, int fa) {
        dfn[u] = ++dep; val[dep] = w[u];
        for (int i=head[u]; ~i; i=edge[i].nex)  {
            int v = edge[i].v;
            if (v == fa)    continue;
            DFS (v, u);
        }
        low[u] = dep;
    }
    
    int main(void)    {
        int T, cas = 0;  scanf ("%d", &T);
        while (T--) {
            if (cas)    puts ("");
            printf ("Case #%d:
    ", ++cas);
            int n, k;   scanf ("%d%d", &n, &k);
            init ();
    
            for (int i=1; i<=n; ++i)    {
                scanf ("%d", &w[i]);
            }
            compress (n);                                           //离散化,升序排序,相同的还是相同的
    
            for (int u, v, i=1; i<n; ++i)   {
                scanf ("%d%d", &u, &v);
                add_edge (u, v);    add_edge (v, u);
            }
            DFS (1, -1);                                            //先序遍历,得到DFS序,树形变线形
    
            int m;  scanf ("%d", &m);
            for (int u, i=1; i<=m; ++i)    {
                scanf ("%d", &u);
                q[i] = Query (dfn[u], low[u], i);
            }
            sort (q+1, q+1+m);                                      //按照DFS序排序
            
            for (int i=1; i<=n; ++i)    cnt[i].clear ();
            int qu = 1; bit.init ();
            for (int i=1; i<=n; ++i)    {                           //按照dep深度从小到大
                int v = val[i];
                cnt[v].push_back (i);                               //表示离散后的相同的权值的个数
                int sz = cnt[v].size ();
                if (sz >= k)    {
                    if (sz == k)    bit.updata (cnt[v][sz-k], 1);
                    else    {
                        bit.updata (cnt[v][sz-k-1], -2);            //?
                        bit.updata (cnt[v][sz-k], 1);
                    }
                }
                while (qu <= m && q[qu].r == i) {
                    ans[q[qu].id] = bit.query (q[qu].r) - bit.query (q[qu].l - 1);
                    qu++;
                }
            }
    
            for (int i=1; i<=m; ++i)    {
                printf ("%d
    ", ans[i]);
            }
        }
    
        return 0;
    }
    

    代码(莫队算法):

    /************************************************
    * Author        :Running_Time
    * Created Time  :2015/9/10 星期四 19:15:22
    * File Name     :I.cpp
     ************************************************/
     
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <sstream>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <vector>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <list>
    #include <map>
    #include <set>
    #include <bitset>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
     
    #define lson l, mid, rt << 1
    #define rson mid + 1, r, rt << 1 | 1
    typedef long long ll;
    const int N = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e9 + 7;
    struct Edge {
        int v, nex;
    }edge[N*2];
    struct Data {
        int l, r, id, b;
        Data () {}
        Data (int l, int r, int id, int b) : l (l), r (r), id (id), b (b) {}
        bool operator < (const Data &x) const {
            if (b == x.b)   return r < x.r;
            else    return b < x.b;
        }
    }data[N];
    int head[N], dfn[N], low[N], w[N], p[N], val[N], ans[N];
    int cnt[N];
    int n, k, m, e, dep, sum;
     
    void init(void) {
        memset (head, -1, sizeof (head));
        e = 0;  dep = 0;
    }
     
    void add_edge(int u, int v) {
        edge[e].v = v;  edge[e].nex = head[u];
        head[u] = e++;
    }
     
    bool cmp(int i, int j)  {
        return w[i] < w[j];
    }
     
    void compress(int n)    {
        for (int i=1; i<=n; ++i)    p[i] = i;
        sort (p+1, p+1+n, cmp);
        int rk = 0, pre = w[p[1]] - 1;
        for (int i=1; i<=n; ++i)    {
            if (pre != w[p[i]]) {
                pre = w[p[i]];
                w[p[i]] = ++rk;
            }
            else    {
                w[p[i]] = rk;
            }
        }
    }
     
    void DFS(int u, int fa) {
        dfn[u] = ++dep; val[dep] = w[u];
        for (int i=head[u]; ~i; i=edge[i].nex)  {
            int v = edge[i].v;
            if (v == fa)    continue;
            DFS (v, u);
        }
        low[u] = dep;
    }
     
    inline void updata(int x, int c)    {
        cnt[x] += c;
        if (cnt[x] == k)    sum++;
        else if (c > 0 && cnt[x] == k + 1) sum--;
        else if (c < 0 && cnt[x] == k - 1)  sum--;
    }
     
    void Modui(void)    {
        memset (cnt, 0, sizeof (cnt));
        sum = 0;
        int l = 1, r = 0;
        for (int i=1; i<=m; ++i)    {
            while (data[i].l < l)   updata (val[--l], 1);
            while (data[i].l > l)   updata (val[l], -1), l++;
            while (data[i].r > r)   updata (val[++r], 1);
            while (data[i].r < r)   updata (val[r], -1), r--;
            ans[data[i].id] = sum;
        }
        for (int i=1; i<=m; ++i)    {
            printf ("%d
    ", ans[i]);
        }
    }
     
    int main(void)    {
        int T, cas = 0;  scanf ("%d", &T);
        while (T--) {
            if (cas)    puts ("");
            printf ("Case #%d:
    ", ++cas);
            scanf ("%d%d", &n, &k);
            init ();
     
            for (int i=1; i<=n; ++i)    {
                scanf ("%d", &w[i]);
            }
            compress (n);                                           //离散化,升序排序,相同的还是相同的
     
            for (int u, v, i=1; i<n; ++i)   {
                scanf ("%d%d", &u, &v);
                add_edge (u, v);    add_edge (v, u);
            }
            DFS (1, -1);                                            //先序遍历,得到DFS序,树形变线形
     
            int block = (int) sqrt (n + 0.5);
            scanf ("%d", &m);
            for (int u, i=1; i<=m; ++i)    {
                scanf ("%d", &u);
                data[i] = Data (dfn[u], low[u], i, dfn[u] / block);
            }
            sort (data+1, data+1+m);                                //按照DFS序排序
            Modui ();
        }
     
        return 0;
    }
    

      

    Codeforces Round #136 (Div. 1) B. Little Elephant and Array

    题目传送门

    分析:估计这是上面那道题的母题(弱化版),直接套用就行了,现在稍微理解了树状数组的维护方法,配上图:

    代码(树状数组):

    /************************************************
    * Author        :Running_Time
    * Created Time  :2015/9/11 星期五 18:39:17
    * File Name     :B.cpp
     ************************************************/
    
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <sstream>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <vector>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <list>
    #include <map>
    #include <set>
    #include <bitset>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    
    #define lson l, mid, rt << 1
    #define rson mid + 1, r, rt << 1 | 1
    typedef long long ll;
    const int N = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e9 + 7;
    int n, m;
    struct BIT  {
        int c[N];
        void init(void) {
            memset (c, 0, sizeof (c));
        }
        void updata(int i, int x)   {
            while (i <= n)  {
                c[i] += x;  i += i & (-i);
            }
        }
        int query(int i)    {
            int ret = 0;
            while (i)   {
                ret += c[i];    i -= i & (-i);
            }
            return ret;
        }
    }bit;
    struct Query    {
        int l, r, id;
        bool operator < (const Query &x) const  {
            return r < x.r;
        }
    }q[N];
    int a[N], ans[N];
    vector<int> cnt[N];
    
    int main(void)    {
        scanf ("%d%d", &n, &m);
        for (int i=1; i<=n; ++i)    scanf ("%d", &a[i]);
        for (int i=1; i<=m; ++i)    {
            scanf ("%d%d", &q[i].l, &q[i].r);
            q[i].id = i;
        }
        sort (q+1, q+1+m);
        int qu = 1;
        for (int i=1; i<=n; ++i)    cnt[i].clear ();
        bit.init ();
        for (int i=1; i<=n; ++i)    {
            if (a[i] > n)   continue;
            cnt[a[i]].push_back (i);
            int sz = cnt[a[i]].size ();
            if (sz >= a[i]) {
                bit.updata (cnt[a[i]][sz-a[i]], 1);
                if (sz > a[i])  bit.updata (cnt[a[i]][sz-a[i]-1], -2);
                if (sz > a[i] + 1)  bit.updata (cnt[a[i]][sz-a[i]-2], 1);
            }
            while (qu <= m && q[qu].r == i) {
                ans[q[qu].id] = bit.query (q[qu].r) - bit.query (q[qu].l - 1);
                qu++;
            }
        }
        for (int i=1; i<=m; ++i)    {
            printf ("%d
    ", ans[i]);
        }
    
        return 0;
    }
    

      

     代码(莫队):

    /************************************************
    * Author        :Running_Time
    * Created Time  :2015/9/11 星期五 20:05:22
    * File Name     :B_Modui.cpp
     ************************************************/
    
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <sstream>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <vector>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <list>
    #include <map>
    #include <set>
    #include <bitset>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    
    #define lson l, mid, rt << 1
    #define rson mid + 1, r, rt << 1 | 1
    typedef long long ll;
    const int N = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e9 + 7;
    struct Data {
        int l, r, id, b;
        bool operator < (const Data &x) const {
            if (b == x.b)   return r < x.r;
            else    return b < x.b;
        }
    }data[N];
    int a[N], ans[N], cnt[N];
    int n, m, sum;
    
    inline void updata(int x, int c) {
        if (x > n)  return ;
        cnt[x] += c;
        if (cnt[x] == x)    sum++;
        else if (c > 0 && cnt[x] == x + 1) sum--;
        else if (c < 0 && cnt[x] == x - 1) sum--;
    }
    
    void Modui(void)    {
        sum = 0;
        memset (cnt, 0, sizeof (cnt));
        int l = 1, r = 0;
        for (int i=1; i<=m; ++i)    {
            while (data[i].l < l)   updata (a[--l], 1);
            while (data[i].l > l)   updata (a[l], -1), l++;
            while (data[i].r > r)   updata (a[++r], 1);
            while (data[i].r < r)   updata (a[r], -1), r--;
            ans[data[i].id] = sum;
        }
        for (int i=1; i<=m; ++i)    {
            printf ("%d
    ", ans[i]);
        }
    }
    
    int main(void)    {
        scanf ("%d%d", &n, &m);
        int block = (int) sqrt (n + 0.5);
        for (int i=1; i<=n; ++i)    {
            scanf ("%d", &a[i]);
        }
        for (int i=1; i<=m; ++i)    {
            scanf ("%d%d", &data[i].l, &data[i].r);
            data[i].id = i; data[i].b = data[i].l / block;
        }
        sort (data+1, data+1+m);
        Modui ();
    
        return 0;
    }
    

      

    编译人生,运行世界!
  • 相关阅读:
    python中kafka生产者和消费者实现
    bzip2压缩
    gzip压缩
    对目录、文件操作需要的权限
    Linux文件查找
    Linux文件种类与扩展名
    centos 文件权限与目录权限
    centos关机命令
    私有方法私有属性继承问题
    python3 中类的__del__方法
  • 原文地址:https://www.cnblogs.com/Running-Time/p/4799169.html
Copyright © 2020-2023  润新知