BIT

POJ 2481

给出n个区间,第i个用\((x_i,y_i)\)表示,定义包含:i包含j等价于\(x_i\leq x_j\land y_j\leq y_i \land\lnot(x_i=x_j\land 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("\n");
    }
    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("\n");
    }
    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\n", GetSum(right[ id[x] ]) - GetSum(id[x]-1));
            }
        }
    }
    return 0;
}
posted @ 2014-12-03 19:43  努力变瘦  阅读(235)  评论(0编辑  收藏  举报