• BIT


    POJ 2481

    给出n个区间,第i个用((x_i,y_i))表示,定义包含:i包含j等价于(x_ileq x_jland y_jleq y_i landlnot(x_i=x_jland y_i=y_j)),问对于每个区间,有多少个区间包含它。

    BIT 做法:将区间排序,对所有i包含j使得i排在j前面,然后从前往后用BIT统计出所求。

    需要注意的地方是两个区间相等的情况的处理,这时可以对原始区间离散化(相同的保存一份,并且统计出个数),在更新时一次更新所有;或者不离散化,每次统计第i个区间时,如果前一个区间和它相同,直接ans[i] = ans[i-1]。

    离散化的代码:

    # include <cstdio>
    # include <cstring>
    # include <algorithm>
    const int maxn = 100005;
    int n;
    int a[maxn], b[maxn], r[maxn], id[maxn];
    int f[maxn], fc[maxn];
    int c[maxn];
    int ans[maxn];
    int lb(int x) {
        return x & -x;
    }
    bool cmp(const int x, const int y) {
        if (a[x] == a[y]) return b[x] > b[y];
        return a[x] < a[y];
    }
    void inc(int x, int cc) {
        for (; x < maxn; x += lb(x)) c[x] += cc;
    }
    int GetSum(int x) {
        int r; for (r = 0; x > 0; x-=lb(x)) r += c[x];
        return r;
    }
    int main()
    {
        while (scanf("%d", &n), n) {
            for (int i = 0; i < n; ++i) {
                scanf("%d%d", &a[i], &b[i]);
                ++a[i], ++b[i];
            }
            for (int i = 0; i < n; ++i) r[i] = i;
            std::sort(r, r+n, cmp);
            int m = 0;
            id[r[0]] = 0;
            f[0] = r[0];
            memset(fc, 0, sizeof(fc));
            ++fc[0];
            for (int i = 1; i < n; ++i) {
                int idx = r[i], pidx = r[i-1];
                if (a[idx]!=a[pidx] || b[idx]!=b[pidx]) ++m, f[m] = idx;
                ++fc[m];
                id[idx] = m;
            }
            ++m;
            memset(c, 0, sizeof(c));
            for (int i = 0; i < m; ++i) {
                ans[i] = GetSum(maxn-1) - GetSum( b[ f[i] ] - 1 );
                inc( b[ f[i] ], fc[i] );
            }
            for (int i = 0; i < n; ++i) {
                if (i) printf(" ");
                printf("%d", ans[ id[i] ]);
            }
            printf("
    ");
        }
        return 0;
    }

    没有离散化的代码:

    # include <cstring>
    # include <cstdio>
    # include <algorithm>
    int n;
    const int maxn = 100005;
    int mx;
    int x[maxn], y[maxn], r[maxn];
    int c[maxn];
    int ans[maxn];
    bool cmp(const int i, const int j) {
        if (x[i] == x[j]) return y[j] < y[i];
        return x[i] < x[j];
    }
    bool judge(int i)
    {
        if (i) {
            int u = r[i], v = r[i-1];
            if (x[u]==x[v] && y[u]==y[v]) return true;
        }
        return false;
    }
    int lb(int x) {return x&-x;}
    int GetSum(int x) {
        int r; for (r = 0; x>0; x-=lb(x)) r+=c[x]; return r;
    }
    void inc(int x) { for (;x<=mx;x+=lb(x)) ++c[x];}
    int main()
    {
        while (scanf("%d", &n), n) {
            mx = 1;
            for (int i = 0; i < n; ++i) scanf("%d%d", &x[i], &y[i]), mx = std::max(mx, ++y[i]);
            for (int i = 0; i < n; ++i) r[i] = i;
            std::sort(r, r+n, cmp);
            memset(c, 0, sizeof(c[0])*(mx+1));
            memset(ans, 0, sizeof(ans[0])*n);
            for (int i = 0; i < n; ++i) {
                int u = r[i];
                if (judge(i)) ans[u] = ans[ r[i-1] ];
                else ans[u] = GetSum(mx) - GetSum(y[u]-1);
                inc(y[u]);
            }
            for (int i = 0; i < n; ++i) {
                printf(i ? " %d":"%d", ans[i]);
            }
            printf("
    ");
        }
        return 0;
    }

    POJ 3321

    先处理出dfs序列,然后对每颗子树的根直接用BIT统计即可。

    vector 超时了,使用邻接表的代码:

    # include <cstdio>
    # include <cstring>
    const int maxn = 100005;
    int n,m;
    int c[maxn];
    bool a[maxn];
    int id[maxn];
    int right[maxn];
    int cntId;
    int cntEdge;
    int first[maxn], next[maxn*2], wor[maxn*2];
    void Add(int u, int v)
    {
        int head = first[u];
        first[u] = ++cntEdge;
        next[cntEdge] = head;
        wor[cntEdge] = u ^ v;
    }
    void dfs(int u, int fa) {
        id[u] = ++cntId;
        for (int e = first[u]; e != -1; e = next[e]) {
            if (wor[e]!=(u^fa)) dfs(wor[e]^u, u);
        }
        right[ id[u] ] = cntId;
    }
    int lb(int x) {return x&-x;}
    void Update(int x, int cc) {for(;x<=n;x+=lb(x)) c[x]+=cc;}
    int GetSum(int x) { int r; for (r=0;x>0;x-=lb(x)) r+=c[x]; return r;}
    int main()
    {
        while (scanf("%d", &n) != EOF) {
            cntEdge = 0;
            memset(first, -1, sizeof(first));
            for (int i = 1; i < n; ++i) {
                int u, v; scanf("%d%d", &u, &v);
                Add(u, v); Add(v, u);
            }
            cntId = 0;
            dfs(1, -1);
            for (int i = 1; i <= n; ++i) c[i] = lb(i), a[i] = true;
            scanf("%d", &m);
            for (int i = 0; i < m; ++i) {
                char od[5]; int x;
                scanf("%s%d", od, &x);
                if (od[0] == 'C') {
                    a[x] = !a[x];
                    Update(id[x], a[x]?1:-1);
                } else {
                    printf("%d
    ", GetSum(right[ id[x] ]) - GetSum(id[x]-1));
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    微软官方中英文Office2010SP1直接下载地址
    开源协议GUN LGPL
    VS2008安装失败!Microsoft Visual Studio Web 创作组件
    新的类型转换操作符(Type Conversion Operators)
    开源协议GNU GPL
    Visual Studio Ultimate 2012 RC 英文版
    两种老公,两种人生。
    开源协议Apache Licence 2.0
    VS2010 关于 CVT1100 和 LNK1123 的解决办法
    Apache Flink Streaming(DataStream API)
  • 原文地址:https://www.cnblogs.com/txd0u/p/4141062.html
Copyright © 2020-2023  润新知