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; }
时间: 2024-10-22 09:25:26