bzoj刷题记录4.15-4.16
来源:互联网 发布:软件工作室图片 编辑:程序博客网 时间:2024/06/05 04:53
bzoj刷题记录4.15-4.16
bzoj2588: Spoj 10628. Count on a tree
很漂亮的解法。
离散化之后在树上建立主席树,然后二分答案
之后发现二分答案所在区间和主席树上区间是重合的,因此可以一起二分下去,复杂度变成了
#include <bits/stdc++.h>using namespace std;inline long long read() { long long a = 0; int c; do c = getchar(); while(!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}const int MAXN = 101000, lgn = 18;int lc[MAXN*3*lgn], rc[MAXN*3*lgn], sum[MAXN*3*lgn], l[MAXN*3*lgn], r[MAXN*3*lgn];int root[MAXN], depth[MAXN], rk[MAXN], n, m, dx[MAXN];int top = 0;struct node { int to, next;} edge[MAXN*2];int head[MAXN], tp = 0;void push(int i, int j){ ++tp, edge[tp] = (node){j, head[i]}, head[i] = tp; }inline int new_node(int opl, int opr){ return ++top, l[top] = opl, r[top] = opr, lc[top]=rc[top]=sum[top] = 0, top;}void build_tree(int &nd, int opl, int opr){ nd = new_node(opl, opr); if (opl < opr) build_tree(lc[nd], opl, (opl+opr)/2), build_tree(rc[nd], (opl+opr)/2+1, opr);}void insert(int pre, int &nd, int pos){ if (l[pre] == r[pre]) nd = new_node(pos, pos), sum[nd] = sum[pre]+1; // 记得++++++++++ else { nd = new_node(l[pre], r[pre]); int mid = (l[pre] + r[pre])/2; if (pos <= mid) insert(lc[pre], lc[nd], pos), rc[nd] = rc[pre]; else insert(rc[pre], rc[nd], pos), lc[nd] = lc[pre]; sum[nd] = sum[lc[nd]] + sum[rc[nd]]; }}int query(int nd, int opl, int opr){ if (opl > opr || !nd) return 0; if (opl == l[nd] && opr == r[nd]) return sum[nd]; int mid = (l[nd]+r[nd])/2; if (opl > mid) return query(rc[nd], opl, opr); else if (opr <= mid) return query(lc[nd], opl, opr); return query(lc[nd], opl, mid)+query(rc[nd], mid+1, opr);}int fa[MAXN][lgn];void dfs(int nd, int f) // remember to insert 1 first{ fa[nd][0] = f; for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (f == to) continue; depth[to] = depth[nd]+1; insert(root[nd], root[to], rk[to]); dfs(to, nd); }}int lca(int a, int b){ if (depth[a] < depth[b]) swap(a, b); for (int i = 0, dt = depth[a]-depth[b]; i < lgn; i++) if ((1<<i)&dt) a = fa[a][i]; if (a == b) return a; for (int i = lgn-1; i >= 0; i--) if (fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i]; return fa[a][0];}void dx_init(){ memcpy(dx, rk, sizeof rk); sort(dx+1, dx+n+1);}int dx_num(int num){ int l = 1, r = n, mid; while (l <= r) { mid = (l+r)>>1; if (dx[mid] < num) l = mid+1; else r = mid-1; } return l;}void init(){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) rk[i] = read(); dx_init(); for (int i = 1; i <= n; i++) rk[i] = dx_num(rk[i]); for (int i = 1; i < n; i++) { int u, v; u = read(), v = read(); push(u, v), push(v, u); } depth[1] = 0; build_tree(root[0], 1, n); insert(root[0], root[1], rk[1]); dfs(1, 0); for (int j = 1; j < lgn; j++) for (int i = 1; i <= n; i++) fa[i][j] = fa[fa[i][j-1]][j-1];}int ask(int i, int j, int k){ int l = 1, r = n; int lp = lca(i, j), g = fa[lp][0]; int a = root[i], b = root[j], c = root[lp], d = root[g]; while (l < r) { int mid = (l+r)/2; int tmp = sum[lc[a]]+sum[lc[b]]-sum[lc[c]]-sum[lc[d]]; if (tmp < k) k -= tmp, l = mid+1, a = rc[a], b = rc[b], c = rc[c], d = rc[d]; else r = mid, a = lc[a], b = lc[b], c = lc[c], d = lc[d]; } return l;}int main(){ init(); int u, v, k, lastans = 0; for (int i = 1; i <= m; i++) { u = read(), v = read(), k = read(); u ^= lastans; printf("%d", lastans = dx[ask(u, v, k)]); if(i!=m) printf("\n"); } return 0;}
bzoj1066: [SCOI2007]蜥蜴
显然最大流建图…
愉悦身心。
#include <bits/stdc++.h>using namespace std;const int MAXN = 1005, MAXM = MAXN*100, inf = 12345678;struct node { int to, flow, next, neg;} edge[MAXM];int head[MAXN], top = 0;inline void push(int i, int j, int f){ ++top, edge[top] = (node) {j, f, head[i], top+1}, head[i] = top; ++top, edge[top] = (node) {i, 0, head[j], top-1}, head[j] = top;}int vis[MAXN], bfstime = 0, lev[MAXN];queue<int> que;int S = 1001, T = 1002;bool bfs(){ for (que.push(S), vis[S] = ++bfstime, lev[S] = 1; !que.empty(); que.pop()) { int f = que.front(), to, flow; for (int i = head[f]; i; i = edge[i].next) { if (to = edge[i].to, flow = edge[i].flow, vis[to] == bfstime || !flow) continue; vis[to] = bfstime, lev[to] = lev[f]+1, que.push(to); } } return vis[T] == bfstime;}int dfs(int nd, int fl = inf){ if (nd == T || !fl) return fl; int ans = 0, t; for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to, flow = edge[i].flow; if (lev[to] != lev[nd]+1 || !flow) continue; t = dfs(to, min(fl, flow)); ans += t, edge[i].flow -= t; fl -= t, edge[edge[i].neg].flow += t; } if (fl) lev[nd] = -1; return ans;}int dinic(){ int ans = 0; while (bfs()) ans += dfs(S); return ans;}int r, c, d;inline int number(int i, int j, int tp){ return (i-1)*c+j+tp*r*c;}char str[40];int main(){ scanf("%d%d%d", &r, &c, &d); for (int i = 1; i <= r; i++) { scanf("%s", str+1); for (int j = 1; j <= c; j++) { push(number(i, j, 0), number(i, j, 1), str[j]-'0'); if (i <= d || j <= d || r-i+1 <= d || c-j+1 <= d) push(number(i, j, 1), T, inf); } } for (int i = 1; i <= r; i++) for (int j = 1; j <= c; j++) for (int k = 1; k <= r; k++) for (int l = 1; l <= c; l++) if (!(i==k && j==l) && abs(i-k)+abs(j-l) <= d) push(number(i, j, 1), number(k, l, 0), inf); int cnt = 0; for (int i = 1; i <= r; i++) { scanf("%s", str+1); for (int j = 1; j <= c; j++) if (str[j] == 'L') push(S, number(i, j, 0), 1), cnt++; } cout << cnt-dinic() << endl; return 0;}
bzoj3673/3674: 可持久化并查集
学习了一发rope
大法。一个trick是在路径压缩时如果没有修改就不要replace
了,否则会mle.
3673
#include <bits/stdc++.h>#include <ext/rope>using namespace std;using namespace __gnu_cxx;const int MAXN = 2e4+5;rope<int> *fa[MAXN];int findfa(int i, int nd){ if (fa[i]->at(nd)) { int p = findfa(i, fa[i]->at(nd)); fa[i]->replace(nd, p); return p; } return nd;}void link(int T, int i, int j){ int a = findfa(T, i), b = findfa(T, j); if (a != b) fa[T]->replace(a, b);}bool linked(int T, int i, int j){ return findfa(T, i) == findfa(T, j); }int n, m;int a[MAXN];int main(){ scanf("%d%d", &n, &m); memset(a, 0, sizeof a); fa[0] = new rope<int>(a, a+n+1); for (int i = 1; i <= m; i++) { int tp; scanf("%d", &tp); fa[i] = new rope<int>(*fa[i-1]); if (tp == 1) { int u, v; scanf("%d%d", &u, &v); link(i, u, v); } else if (tp == 2) { int k; scanf("%d", &k); if (k >= i) continue; fa[i] = new rope<int>(*fa[k]); } else { int u, v; scanf("%d%d", &u, &v); printf("%d\n", linked(i, u, v)); } } return 0;}
3674
#include <bits/stdc++.h>#include <ext/rope>using namespace std;using namespace __gnu_cxx;const int MAXN = 2e5+5;rope<int> *fa[MAXN];int findfa(int i, int nd){ if (fa[i]->at(nd)) { int p = findfa(i, fa[i]->at(nd)); if (fa[i]->at(nd) != p) fa[i]->replace(nd, p); return p; } return nd;}void link(int T, int i, int j){ int a = findfa(T, i), b = findfa(T, j); if (a != b) fa[T]->replace(a, b);}bool linked(int T, int i, int j){ return findfa(T, i) == findfa(T, j); }int n, m;int a[MAXN];int main(){ scanf("%d%d", &n, &m); memset(a, 0, sizeof a); fa[0] = new rope<int>(a, a+n+1); int lastans = 0; for (int i = 1; i <= m; i++) { int tp; scanf("%d", &tp); fa[i] = new rope<int>(*fa[i-1]); if (tp == 1) { int u, v; scanf("%d%d", &u, &v); u ^= lastans, v ^= lastans; link(i, u, v); } else if (tp == 2) { int k; scanf("%d", &k); k ^= lastans; if (k >= i) continue; fa[i] = new rope<int>(*fa[k]); } else { int u, v; scanf("%d%d", &u, &v); u ^= lastans, v ^= lastans; printf("%d\n", linked(i, u, v)); lastans = linked(i, u, v); } } return 0;}
接下来是一波莫比乌斯反演练习
莫比乌斯函数定义为:
符号
bzoj2440: [中山市选2011]完全平方数
包含平方数
根据容斥原理可以列出小于
前两个东西的乘积就是
由于
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;int not_prime[MAXN], prime[MAXN], top = 0, mu[MAXN];void get_prime(int n){ memset(not_prime, 0, sizeof not_prime); mu[1] = 1; for (int i = 2; i <= n; i++) { if (!not_prime[i]) prime[++top] = i, mu[i] = -1; for (int j = 1; j <= top && prime[j]*i <= n; j++) { not_prime[prime[j]*i] = 1; if (i%prime[j] == 0) { mu[i*prime[j]] = 0; break; } mu[i*prime[j]] = -mu[i]; } }}long long ans(long long n){ long long tp = (long long)(sqrt(n)+0.05); long long ans = 0; for (long long i = 1; i <= tp; i++) ans += mu[i]*(n/(i*i)); return ans;}int main(){ get_prime(100000); int T; scanf("%d", &T); while (T--) { long long n; scanf("%lld", &n); long long l = 1, r = 1e10; while (l <= r) { long long mid = (l+r)/2; if (ans(mid) < n) l = mid+1; else r = mid-1; } cout << l << endl; } return 0;}
bzoj2301: [HAOI2011]Problem b
基本上一下午就在肝这个题…感觉理解力捉急。
首先学习一个
以及莫比乌斯反演定理:
和另一种表现形式:
后一种更常用一些,因为处理
考虑所求的可以用如下式配合容斥原理完成:
设:
则有:
由于:
根据反演定理:
由于后面的除法后取整最多只有
由于:
满足
满足:
由于对称性可以知道:
由此可以知道,于
ans += (sum[last]-sum[i-1])*(p/i/k)*(q/i/k); k = last+1;
就得到了
#include <bits/stdc++.h>using namespace std;const int MAXN = 50005;int prime[MAXN], not_prime[MAXN], mu[MAXN], s[MAXN], top = 0, n;void get_prime(){ mu[1] = 1; for (int i = 2; i <= n; i++) { if (!not_prime[i]) { prime[++top] = i, mu[i] = -1; } for (int j = 1; j <= top && prime[j]*i <= n; j++) { not_prime[prime[j]*i] = 1; if (i%prime[j] == 0) { mu[prime[j]*i] = 0; break; } mu[prime[j]*i] = -mu[i]; } }}void init(){ n = 50000; get_prime(); s[0] = 0; for (int i = 1; i <= n; i++) s[i] = s[i-1] + mu[i];}int f(int x, int p, int q){ int ans = 0, last = 0; if (p > q) swap(p, q); p /= x, q /= x; for (int i = 1; i <= p; i = last+1) { last = min(p/(p/i), q/(q/i)); ans += (s[last]-s[i-1])*(p/i)*(q/i); } return ans;}int f2(int i, int p, int q){ int ans = 0; for (int k = 1; (p/(k*i))*(q/(k*i)); k++) ans += mu[k]*(p/(k*i))*(q/(k*i)); return ans;}int main(){ int a, b, c, d, k; init(); int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d%d%d%d%d", &a, &b, &c, &d, &k); int ans; printf("%d\n", ans = f(k, b, d)-f(k, a-1, d)-f(k, b, c-1)+f(k, a-1, c-1)); } return 0;}
ps:如果能不构造
- bzoj刷题记录4.15-4.16
- BZOJ刷题记录
- BZOJ刷题记录(2014)
- BZOJ 刷题记录 PART 1
- BZOJ 刷题记录 PART 2
- BZOJ 刷题记录 PART 3
- BZOJ 刷题记录 PART 4
- BZOJ 刷题记录 PART 5
- BZOJ 刷题记录 PART 6
- bzoj刷题记录2017.4.2-4.4
- bzoj刷题记录:4.5-4.9
- bzoj刷题记录4.10-4.14
- bzoj刷题记录4.17-4.21
- bzoj刷题记录4.25-5.1
- bzoj刷题记录5.6-5.10
- bzoj刷题记录5.11-5.15
- BZOJ刷题记录(施工到AFO)
- OI刷题记录
- 错误:_csv.Error: line contains NULL byte(已解决)
- 用jquery封装的手风琴特效插件
- Java数据结构与算法《二》简单排序
- 指针和引用的区别
- (贪心)悼念512汶川大地震遇难同胞――老人是真饿了
- bzoj刷题记录4.15-4.16
- C++作业4
- Public Sale
- Java数据结构与算法《三》栈与队列
- Sublime Text3配置Node.js开发环境
- leetcode- 215. Kth Largest Element in an Array(基于快速排序思想)
- Python小练习
- 文章标题
- hive优化--增加减少map数