[关闭]
@ljt12138 2017-06-09T19:30:46.000000Z 字数 16497 阅读 794

各种OJ刷题记录5.31-6.8


bzoj2733: [HNOI2012]永无乡

以前用启发式合并做的,突然脑补出了线段树合并做法,比启发式合并快到不知哪里去了。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. int n, m, k;
  5. int l[MAXN*20], r[MAXN*20], lc[MAXN*20], rc[MAXN*20], dat[MAXN*20];
  6. int top = 0;
  7. int build(int opl, int opr, int pos)
  8. {
  9. int nd = ++top;
  10. l[nd] = opl, r[nd] = opr, dat[nd] = 1;
  11. if (opl < opr) {
  12. int mid = (opl+opr)/2;
  13. if (pos <= mid) lc[nd] = build(opl, mid, pos);
  14. else rc[nd] = build(mid+1, opr, pos);
  15. }
  16. return nd;
  17. }
  18. int merge(int a, int b)
  19. {
  20. if (a==0||b==0) return a+b;
  21. dat[a] += dat[b];
  22. lc[a] = merge(lc[a], lc[b]);
  23. rc[a] = merge(rc[a], rc[b]);
  24. return a;
  25. }
  26. int kth(int nd, int k)
  27. {
  28. int l = 1, r = n;
  29. while (l < r) {
  30. int dt = dat[lc[nd]];
  31. if (dt >= k) r = (l+r)/2, nd = lc[nd];
  32. else k -= dt, l = (l+r)/2+1, nd = rc[nd];
  33. }
  34. return l;
  35. }
  36. int tr[MAXN];
  37. int fa[MAXN];
  38. inline int findf(int i)
  39. { return fa[i]?fa[i]=findf(fa[i]):i; }
  40. int atp[MAXN];
  41. int main()
  42. {
  43. scanf("%d%d", &n, &m);
  44. for (int i = 1; i <= n; i++) {
  45. int d; scanf("%d", &d);
  46. atp[d] = i;
  47. tr[i] = build(1, n, d);
  48. }
  49. for (int i = 1; i <= m; i++) {
  50. int u, v;
  51. scanf("%d%d", &u, &v);
  52. u = findf(u), v = findf(v);
  53. if (u != v) fa[u] = v, tr[v] = merge(tr[u], tr[v]);
  54. }
  55. scanf("%d", &k);
  56. char str[3];
  57. int u, v;
  58. for (int i = 1; i <= k; i++) {
  59. scanf("%s %d %d", str, &u, &v);
  60. if (str[0] == 'B') {
  61. u = findf(u), v = findf(v);
  62. if (u != v) fa[u] = v, tr[v] = merge(tr[u], tr[v]);
  63. } else {
  64. u = findf(u);
  65. if (dat[tr[u]] < v) puts("-1");
  66. else printf("%d\n", atp[kth(tr[u], v)]);
  67. }
  68. }
  69. return 0;
  70. }

bzoj3996: [TJOI2015]线性代数

以前觉得挺神的题...推了推发现还是很水的。

容易发现:

由于向量,有贡献当且仅当,而则在为时为负权,因此可以构造最大权闭合子图:为正权点,为负权点,依赖,然后套板子就好了。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 501*501+1005;
  4. struct node {
  5. int to, next, flow, neg;
  6. } edge[MAXN*10];
  7. int head[MAXN], top = 0;
  8. inline void push(int i, int j, int f)
  9. {
  10. ++top, edge[top] = (node){j, head[i], f, top+1}, head[i] = top;
  11. ++top, edge[top] = (node){i, head[j], 0, top-1}, head[j] = top;
  12. }
  13. int vis[MAXN], bfstime = 0;
  14. int lev[MAXN];
  15. int S = MAXN-3, T = MAXN-2;
  16. queue<int> que;
  17. bool bfs()
  18. {
  19. vis[S] = ++bfstime, lev[S] = 0, que.push(S);
  20. while (!que.empty()) {
  21. int nd = que.front(); que.pop();
  22. for (int i = head[nd]; i; i = edge[i].next) {
  23. int to = edge[i].to, f = edge[i].flow;
  24. if (vis[to] == bfstime || !f) continue;
  25. vis[to] = bfstime, que.push(to), lev[to] = lev[nd]+1;
  26. }
  27. }
  28. return vis[T] == bfstime;
  29. }
  30. int dfs(int nd, int flow)
  31. {
  32. if (nd == T || !flow) return flow;
  33. int ans = 0, t;
  34. for (int i = head[nd]; i; i = edge[i].next) {
  35. int to = edge[i].to, f = edge[i].flow;
  36. if (lev[to] != lev[nd]+1 || !f) continue;
  37. t = dfs(to, min(flow, f));
  38. ans += t, edge[i].flow -= t;
  39. edge[edge[i].neg].flow += t, flow -= t;
  40. }
  41. if (flow) lev[nd] = -1;
  42. return ans;
  43. }
  44. int dinic()
  45. {
  46. int ans = 0;
  47. while (bfs()) ans += dfs(S, 233333333);
  48. return ans;
  49. }
  50. int B[505][505], n, c[MAXN];
  51. int main()
  52. {
  53. scanf("%d", &n);
  54. int ans = 0;
  55. for (int i = 1; i <= n; i++)
  56. for (int j = 1; j <= n; j++)
  57. scanf("%d", &B[i][j]), ans += B[i][j];
  58. for (int i = 1; i <= n; i++)
  59. scanf("%d", &c[i]);
  60. for (int i = 1; i <= n; i++)
  61. for (int j = 1; j <= n; j++) {
  62. int dat = (i-1)*n+j;
  63. push(S, dat, B[i][j]);
  64. push(dat, n*n+i, 233333333);
  65. push(dat, n*n+j, 233333333);
  66. }
  67. for (int i = 1; i <= n; i++)
  68. push(n*n+i, T, c[i]);
  69. cout << ans-dinic() << endl;
  70. return 0;
  71. }

LYOI#158. 「上下界网络流」有源汇最小流

向Orz stdcall学习了一个上下界最大最小流的姿势:

  1. 上下界最小流:先求不加入的最大流,记录为,再在残量网络上加入,求最大流为。设辅助边容量和,则则无解,否则就是结果。
  2. 上下界最大流:先加入,跑一个的最大流;跑不满辅助边就无解。然后跑的最大流。结果就是上的流量。

这题需要当前弧一下,跑得比香港记者还快。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 50010, MAXM = 100227*10;
  4. struct node {
  5. int to, next, flow, neg;
  6. } edge[MAXM];
  7. int head[MAXN], top = 0;
  8. inline void push(int i, int j, int f)
  9. {
  10. ++top, edge[top] = (node){j, head[i], f, top+1}, head[i] = top;
  11. ++top, edge[top] = (node){i, head[j], 0, top-1}, head[j] = top;
  12. }
  13. int SS = 50007, ST = 50008;
  14. int inf = 2147483647;
  15. int lev[MAXN], vis[MAXN], bfstime = 0;
  16. queue<int> que;
  17. int n, m, s, t;
  18. bool bfs()
  19. {
  20. lev[SS] = 1, vis[SS] = ++bfstime;
  21. que.push(SS);
  22. while (!que.empty()) {
  23. int nd = que.front(); que.pop();
  24. for (int i = head[nd]; i; i = edge[i].next) {
  25. int to = edge[i].to, f = edge[i].flow;
  26. if (vis[to] == bfstime || !f) continue;
  27. lev[to] = lev[nd]+1, que.push(to), vis[to] = bfstime;
  28. }
  29. }
  30. return vis[ST] == bfstime;
  31. }
  32. int cur[MAXN];
  33. long long dfs(int nd, int maxf)
  34. {
  35. if (nd == ST || !maxf) return maxf;
  36. long long ans = 0;
  37. int t;
  38. for (register int &i = cur[nd]; i; i = edge[i].next) {
  39. int to = edge[i].to, f = edge[i].flow;
  40. if (lev[to] != lev[nd]+1 || !f) continue;
  41. t = dfs(to, min(f, maxf));
  42. ans += t, maxf -= t;
  43. edge[i].flow -= t, edge[edge[i].neg].flow += t;
  44. if (!maxf) break;
  45. }
  46. if (maxf) lev[nd] = -1;
  47. return ans;
  48. }
  49. long long dinic()
  50. {
  51. long long ans = 0;
  52. while (bfs()) {
  53. for (int i = 1; i <= n; i++) cur[i] = head[i];
  54. cur[SS] = head[SS], cur[ST] = head[ST];
  55. ans += dfs(SS, inf);//, printf("%lld\n", ans);
  56. }
  57. return ans;
  58. }
  59. int main()
  60. {
  61. scanf("%d%d%d%d", &n, &m, &s, &t);
  62. long long cnt = 0;
  63. for (int i = 1; i <= m; i++) {
  64. int u, v, l, r;
  65. scanf("%d%d%d%d", &u, &v, &l, &r);
  66. push(u, v, r-l), push(SS, v, l), push(u, ST, l);
  67. cnt += l;
  68. }
  69. long long k = dinic();
  70. push(t, s, inf);
  71. long long ans = dinic();
  72. if (k+ans < cnt) puts("please go home to sleep");
  73. else cout << ans << endl;
  74. return 0;
  75. }

bzoj1492: [NOI2007]货币兑换Cash

好好做一个斜率优化...

首先是一个贪心性质,每次交易一定是的。

然后可以设为第天手上最多为第天最多的钱,根据题目有:

然后找递推关系:

有:

后面的,对于一大堆点要最大化轴截距,则要维护一个上凸壳。然而这次斜率不随单调,因此不能用单调队列,而要用维护凸包。

考虑用分治解决这个问题。首先按斜率排序询问。过程用来求解内所有,并将按横坐标排序。考虑先划分成;递归处理。然后得到了左边所有节点排好序的结果,用一个单调栈维护上凸壳。右边所有询问按斜率排序过了,直接扫一遍更新。然后就可以递归处理右边。

最后只剩一个问题,就是按排序。这里只要用归并两个区间就可以了。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. int n, m;
  5. double f[MAXN];
  6. const double eps = 1e-7, inf = 1e9;
  7. struct query {
  8. double a, b, r;
  9. int pos;
  10. inline double slop()
  11. {
  12. return -a/b;
  13. }
  14. } q[MAXN], tmp[MAXN];
  15. struct point {
  16. double x, y;
  17. friend bool operator < (const point &a, const point &b)
  18. { return b.x-a.x>eps||(abs(b.x-a.x)<=eps && b.y-a.y > eps); }
  19. } stk[MAXN], p[MAXN], tmp_p[MAXN];
  20. int top;
  21. inline double slop(const point &a, const point &b)
  22. {
  23. if (abs(a.x-b.x)<=eps) return -inf;
  24. return (a.y-b.y)/(a.x-b.x);
  25. }
  26. bool cmp(query a, query b)
  27. { return a.slop() > b.slop(); }
  28. void solve(int l, int r)
  29. {
  30. if (l == r) {
  31. f[l] = max(f[l], f[l-1]);
  32. p[l].y = f[l]/(q[l].a*q[l].r+q[l].b), p[l].x = q[l].r*p[l].y;
  33. return;
  34. }
  35. int mid = (l+r)>>1, l1 = l, l2 = mid+1;
  36. for (int i = l; i <= r; i++) {
  37. if (q[i].pos <= mid) tmp[l1++] = q[i];
  38. else tmp[l2++] = q[i];
  39. }
  40. for (int i = l; i <= r; i++)
  41. q[i] = tmp[i];
  42. solve(l, mid);
  43. top = 0;
  44. for (int i = l; i <= mid; i++) {
  45. while (top >= 2 && slop(stk[top-1], stk[top]) < slop(stk[top], p[i])-eps) top--;
  46. stk[++top] = p[i];
  47. }
  48. int lp = 1;
  49. for (int i = mid+1; i <= r; i++) {
  50. while (lp+1 <= top && slop(stk[lp], stk[lp+1]) > q[i].slop()-eps) lp++;
  51. f[q[i].pos] = max(f[q[i].pos], stk[lp].x*q[i].a+stk[lp].y*q[i].b);
  52. }
  53. solve(mid+1, r);
  54. int tp = l, a = l, b = mid+1;
  55. while (a <= mid && b <= r) {
  56. if (p[a] < p[b]) tmp_p[tp++] = p[a++];
  57. else tmp_p[tp++] = p[b++];
  58. }
  59. while (a <= mid) tmp_p[tp++] = p[a++];
  60. while (b <= r) tmp_p[tp++] = p[b++];
  61. for (int i = l; i <= r; i++)
  62. p[i] = tmp_p[i];
  63. }
  64. int main()
  65. {
  66. // freopen("cash.in", "r", stdin);
  67. // freopen("cash.out", "w", stdout);
  68. scanf("%d%lf", &n, &f[0]);
  69. for (int i = 1; i <= n; i++) {
  70. scanf("%lf%lf%lf", &q[i].a, &q[i].b, &q[i].r);
  71. q[i].pos = i;
  72. }
  73. sort(q+1, q+n+1, cmp);
  74. solve(1, n);
  75. printf("%.3f\n", f[n]);
  76. return 0;
  77. }

cf717G. Underfail

题意:给定主串和模式串,每个模式串有权值,在某个位置匹配一次可以获取权值。主串每个位置最多被匹配次,问最大权值和。

首先用自动机找出所有的匹配位置(记录所有经过的位置,他在树上的祖先即是所有匹配位置),然后就变成了一个区间最大权覆盖的模型。

然后就是网络流套路(类似志愿者招募那个模型)了:

  1. ,之间表示第个位置,容量为
  2. 对于一个覆盖,流量为,费用为

考虑增广路的形态,显然由于从左向右连,不会有相交环干扰,每一条增广路都是不相交的环组成的。而流量则限制了跨越他的环最多只有个,而下面的流量,所以存在一个的割,根据最大流最小割定理,,满足了最多被覆盖次的限制。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int n, m, p[105], x;
  4. int len[105];
  5. char str[505], s[505];
  6. const int MAXN = 500*100;
  7. struct node {
  8. int to, next, flow, cost, neg;
  9. } edge[500*500];
  10. int head[MAXN], tp = 0;
  11. inline void push(int i, int j, int f, int c)
  12. {
  13. ++tp, edge[tp] = (node){j, head[i], f, c, tp+1}, head[i] = tp;
  14. ++tp, edge[tp] = (node){i, head[j], 0, -c, tp-1}, head[j] = tp;
  15. }
  16. int dis[MAXN], vis[MAXN];
  17. queue<int> q;
  18. int pre[MAXN], pre_edge[MAXN];
  19. int S = MAXN-3, T = MAXN-2;
  20. bool spfa(int &flow, int &cost)
  21. {
  22. memset(dis, 127/3, sizeof dis);
  23. dis[S] = 0, q.push(S), vis[S] = 1;
  24. while (!q.empty()) {
  25. int nd = q.front(); q.pop(); vis[nd] = 0;
  26. // cerr << nd << endl;
  27. for (int i = head[nd]; i; i = edge[i].next) {
  28. int f = edge[i].flow, c = edge[i].cost;
  29. int to = edge[i].to;
  30. if (!f || dis[to] <= dis[nd]+c) continue;
  31. dis[to] = dis[nd]+c, pre[to] = nd, pre_edge[to] = i;
  32. if (!vis[to]) vis[to] = 1, q.push(to);
  33. }
  34. }
  35. if (dis[T] >= 233333333) return 0;
  36. int mf = INT_MAX;
  37. for (int i = T; i != S; i = pre[i]) mf = min(mf, edge[pre_edge[i]].flow);
  38. for (int i = T; i != S; i = pre[i]) edge[pre_edge[i]].flow -= mf, edge[edge[pre_edge[i]].neg].flow += mf;
  39. flow += mf, cost += mf*dis[T];
  40. return 1;
  41. }
  42. void mcf(int &flow, int &cost)
  43. {
  44. flow = cost = 0;
  45. while (spfa(flow, cost));// printf("...%d\n", cost);
  46. }
  47. void push_edge(int l, int r, int v)
  48. {
  49. push(l, r+1, 1, -v);
  50. }
  51. void push_init()
  52. {
  53. for (int i = 1; i <= n; i++)
  54. push(i, i+1, x, 0);
  55. push(S, 1, x, 0), push(n+1, T, x, 0);
  56. }
  57. int fail[MAXN], chl[MAXN][26], fin[MAXN];
  58. vector<int> pos[MAXN];
  59. int root = 0, top = 0;
  60. void push(int &nd, const char *str, int id)
  61. {
  62. if (!nd) nd = ++top;
  63. if (*str == '\0') fin[nd] = id;
  64. else push(chl[nd][*str-'a'], str+1, id);
  65. }
  66. queue<int> que;
  67. void init()
  68. {
  69. fail[root] = 0, que.push(root);
  70. while (!que.empty()) {
  71. int nd = que.front(); que.pop();
  72. for (int i = 0; i < 26; i++) {
  73. if (!chl[nd][i]) continue;
  74. int p = fail[nd];
  75. while (p && !chl[p][i]) p = fail[p];
  76. if (p) fail[chl[nd][i]] = chl[p][i];
  77. else fail[chl[nd][i]] = root;
  78. que.push(chl[nd][i]);
  79. }
  80. }
  81. }
  82. void match(int nd, const char *str, int ps)
  83. {
  84. for (int i = nd; i; i = fail[i])
  85. if (fin[i]) push_edge(ps-len[fin[i]]+1, ps, p[fin[i]]);
  86. if (*str == '\0') return;
  87. while (nd && !chl[nd][*str-'a']) nd = fail[nd];
  88. if (!nd) match(root, str+1, ps+1);
  89. else match(chl[nd][*str-'a'], str+1, ps+1);
  90. }
  91. int main()
  92. {
  93. scanf("%d", &n);
  94. scanf("%s", str);
  95. scanf("%d", &m);
  96. for (int i = 1; i <= m; i++) {
  97. scanf("%s %d", s, &p[i]), len[i] = strlen(s);
  98. push(root, s, i);
  99. }
  100. scanf("%d", &x);
  101. push_init();
  102. init();
  103. match(root, str, 0);
  104. int flow = 0, cost = 0;
  105. mcf(flow, cost);
  106. cout << -cost << endl;
  107. return 0;
  108. }

bzoj3622: 已经没有什么好害怕的了

广义容斥原理...
http://www.cnblogs.com/candy99/p/6617195.html

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 2005;
  4. int sug[MAXN], med[MAXN], n, k;
  5. int cnt[MAXN], fac[MAXN];
  6. const int mod = 1e9+9;
  7. int f[MAXN][MAXN], a[MAXN];
  8. int power(int a, int n)
  9. {
  10. int b = a, ans = 1;
  11. for (int i = 0; i <= 30; i++) {
  12. if (n&(1<<i)) ans = (long long)ans*b%mod;
  13. b = (long long)b*b%mod;
  14. }
  15. return ans;
  16. }
  17. int inv(int a)
  18. { return power(a, mod-2); }
  19. int choose(int n, int k)
  20. { return (long long)fac[n]*inv(fac[k])%mod*inv(fac[n-k])%mod; }
  21. int main()
  22. {
  23. scanf("%d%d", &n, &k);
  24. if ((n+k)&1) { printf("0\n"); return 0; }
  25. else k = (n+k)>>1;
  26. for (int i = 1; i <= n; i++) scanf("%d", &sug[i]);
  27. for (int i = 1; i <= n; i++) scanf("%d", &med[i]);
  28. fac[0] = 1;
  29. for (int i = 1; i <= n; i++) fac[i] = (long long)fac[i-1]*i%mod;
  30. sort(sug+1, sug+n+1), sort(med+1, med+n+1);
  31. int l = 0;
  32. for (int i = 1; i <= n; i++) {
  33. while (l < n && med[l+1] < sug[i]) l++;
  34. cnt[i] = l;
  35. }
  36. f[0][0] = 1;
  37. for (int i = 1; i <= n; i++) {
  38. for (int j = 0; j <= n; j++) {
  39. f[i][j] = f[i-1][j];
  40. if (j>0)
  41. f[i][j] = (f[i][j]+(long long)f[i-1][j-1]*max(cnt[i]-j+1, 0)%mod)%mod;
  42. }
  43. }
  44. for (int i = 0; i <= n; i++) a[i] = (long long)f[n][i]*fac[n-i]%mod;
  45. int ans = 0;
  46. for (int i = k; i <= n; i++)
  47. ans = (ans+(((i-k)&1)?-1:1)*(long long)choose(i, k)*a[i]%mod)%mod;
  48. cout << (ans%mod+mod)%mod << endl;
  49. return 0;
  50. }

bzoj3339: Rmq Problem

常规方法不太好处理。
hzwer给出了一个思路:将询问按排序,用数据结构维护当前左端点下各个右端点的结果。然后计算每次移动左区间对后面值的影响。

具体到这道题,首先用并查集或者树状数组上二分求出初始时的,并预处理出每个值下一个这种值的位置。考虑更新到的影响就是将中所有大于的变成,也就是取。这显然可以用线段树维护。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 200005, inf = 233333333;
  4. int fa[MAXN];
  5. inline int findf(int nd)
  6. { return fa[nd]!=nd?fa[nd]=findf(fa[nd]):nd; }
  7. void link(int i, int j)
  8. {
  9. int a = findf(i), b = findf(j);
  10. if (a != b) fa[a] = b;
  11. }
  12. int a[MAXN], nxt[MAXN], now[MAXN];
  13. int n, q;
  14. int mex[MAXN];
  15. struct tree {
  16. int l[MAXN*4], r[MAXN*4], lc[MAXN*4], rc[MAXN*4], tag[MAXN*4], dat[MAXN*4];
  17. int top, root;
  18. void clear()
  19. { top = root = 0; }
  20. void build(int &nd, int opl, int opr)
  21. {
  22. nd = ++top, l[nd] = opl, r[nd] = opr, tag[nd] = inf;
  23. if (opl < opr)
  24. build(lc[nd], opl, (opl+opr)>>1), build(rc[nd], ((opl+opr)>>1)+1, opr);
  25. else dat[nd] = mex[opl];
  26. }
  27. void pdw(int nd)
  28. {
  29. if (tag[nd] == inf) return;
  30. if (lc[nd]) tag[lc[nd]] = min(tag[lc[nd]], tag[nd]), tag[rc[nd]] = min(tag[rc[nd]], tag[nd]), tag[nd] = inf;
  31. else dat[nd] = min(dat[nd], tag[nd]), tag[nd] = inf;
  32. }
  33. void modify(int nd, int opl, int opr, int dt) // 区间内大于dt的变为dt
  34. {
  35. if (opl > opr) return;
  36. pdw(nd);
  37. if (l[nd] == opl && r[nd] == opr) tag[nd] = min(tag[nd], dt);
  38. else {
  39. int mid = (l[nd]+r[nd])>>1;
  40. if (opr <= mid) modify(lc[nd], opl, opr, dt);
  41. else if (opl > mid) modify(rc[nd], opl, opr, dt);
  42. else modify(lc[nd], opl, mid, dt), modify(rc[nd], mid+1, opr, dt);
  43. }
  44. }
  45. int query(int nd, int dt)
  46. {
  47. pdw(nd);
  48. if (l[nd] == r[nd]) return dat[nd];
  49. else {
  50. int mid = (l[nd]+r[nd])>>1;
  51. if (dt <= mid) return query(lc[nd], dt);
  52. else return query(rc[nd], dt);
  53. }
  54. }
  55. } seg;
  56. int last[MAXN];
  57. struct qy {
  58. int l, r, id, ans;
  59. friend bool operator < (const qy &a, const qy &b)
  60. { return a.l < b.l; }
  61. } qs[MAXN];
  62. int ans[MAXN];
  63. int main()
  64. {
  65. scanf("%d%d", &n, &q);
  66. for (int i = 0; i <= n; i++) fa[i] = i;
  67. for (int i = 1; i <= n; i++)
  68. scanf("%d", &a[i]);
  69. for (int i = 1; i <= n; i++) {
  70. now[a[i]] = 1;
  71. if (a[i]-1>=0&&now[a[i]-1]) link(a[i]-1, a[i]);
  72. if (now[a[i]+1]) link(a[i], a[i]+1);
  73. mex[i] = now[0]?findf(0)+1:0;
  74. } // 并查集维护初始mex
  75. for (int i = 1; i <= n; i++) {
  76. if (last[a[i]]) nxt[last[a[i]]] = i;
  77. last[a[i]] = i;
  78. }
  79. for (int i = 1; i <= n; i++)
  80. if (nxt[i] == 0) nxt[i] = n+1;
  81. seg.build(seg.root, 1, n); // 初始值
  82. for (int i = 1; i <= q; i++) scanf("%d%d", &qs[i].l, &qs[i].r), qs[i].id = i;
  83. sort(qs+1, qs+q+1);
  84. int now = 1;
  85. for (int i = 1; i <= n; i++) {
  86. while (now <= q && qs[now].l == i) {
  87. ans[qs[now].id] = seg.query(seg.root, qs[now].r);
  88. now++;
  89. }
  90. seg.modify(seg.root, i, nxt[i]-1, a[i]);
  91. }
  92. for (int i = 1; i <= q; i++)
  93. printf("%d\n", ans[i]);
  94. return 0;
  95. }

COGS2648.[IOI2011]Race

1A了...感慨万千...

OI中摩尔定律:知识量随时间以指数增长,题目难度随时间以指数降低。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 200005;
  4. struct node {
  5. int to, next, dis;
  6. } edge[MAXN*2];
  7. int head[MAXN], top = 0;
  8. void push(int i, int j, int d)
  9. { edge[++top] = (node){j, head[i], d}, head[i] = top; }
  10. int siz[MAXN], vis[MAXN];
  11. void dfs_siz(int nd, int f)
  12. {
  13. siz[nd] = 1;
  14. for (int i = head[nd]; i; i = edge[i].next) {
  15. int to = edge[i].to;
  16. if (to == f || vis[to]) continue;
  17. dfs_siz(to, nd), siz[nd] += siz[to];
  18. }
  19. }
  20. void dfs_sel(int nd, int f, const int totsiz, int &ans, int &maxl)
  21. {
  22. int maxs = 0;
  23. if (f) maxs = totsiz-siz[nd];
  24. for (int i = head[nd]; i; i = edge[i].next) {
  25. int to = edge[i].to;
  26. if (to == f || vis[to]) continue;
  27. maxs = max(maxs, siz[to]);
  28. }
  29. if (maxs < maxl) maxl = maxs, ans = nd;
  30. for (int i = head[nd]; i; i = edge[i].next) {
  31. int to = edge[i].to;
  32. if (to == f || vis[to]) continue;
  33. dfs_sel(to, nd, totsiz, ans, maxl);
  34. }
  35. }
  36. int sig[1000005];
  37. int n, k, pans = 233333333, cnt = 233333333;
  38. void dfs_calc(int nd, int f, int dep, int now_len)
  39. {
  40. if (now_len > k) return;
  41. cnt = min(cnt, sig[k-now_len]+dep);
  42. for (int i = head[nd]; i; i = edge[i].next) {
  43. int to = edge[i].to;
  44. if (to == f || vis[to]) continue;
  45. dfs_calc(to, nd, dep+1, now_len+edge[i].dis);
  46. }
  47. }
  48. void dfs_mod(int nd, int f, int dep, int now_len)
  49. {
  50. if (now_len > k) return;
  51. sig[now_len] = min(sig[now_len], dep);
  52. for (int i = head[nd]; i; i = edge[i].next) {
  53. int to = edge[i].to;
  54. if (to == f || vis[to]) continue;
  55. dfs_mod(to, nd, dep+1, now_len+edge[i].dis);
  56. }
  57. }
  58. void dfs_dec(int nd, int f, int dep, int now_len)
  59. {
  60. if (now_len > k) return;
  61. sig[now_len] = 233333333;
  62. for (int i = head[nd]; i; i = edge[i].next) {
  63. int to = edge[i].to;
  64. if (to == f || vis[to]) continue;
  65. dfs_dec(to, nd, dep+1, now_len+edge[i].dis);
  66. }
  67. }
  68. void calc(int nd)
  69. {
  70. dfs_siz(nd, 0);
  71. int center = 0, ans = 233333333;
  72. dfs_sel(nd, 0, siz[nd], center, ans);
  73. // cerr << center << endl;
  74. vis[center] = 1, cnt = 233333333, sig[0] = 0;
  75. for (int i = head[center]; i; i = edge[i].next) {
  76. int to = edge[i].to, d = edge[i].dis;
  77. if (vis[to]) continue;
  78. dfs_calc(to, 0, 1, d), dfs_mod(to, 0, 1, d);
  79. // cerr << to << endl;
  80. // for (int j = 1; j <= k; j++)
  81. // cerr << sig[j] << " ";
  82. // cerr << endl << cnt << endl;
  83. }
  84. pans = min(pans, cnt);
  85. // cerr << "gg" << ans << endl;
  86. dfs_dec(center, 0, 0, 0);
  87. for (int i = head[center]; i; i = edge[i].next) {
  88. int to = edge[i].to;
  89. if (vis[to]) continue;
  90. calc(to);
  91. }
  92. }
  93. int main()
  94. {
  95. freopen("ioi2011-race.in", "r", stdin);
  96. freopen("ioi2011-race.out", "w", stdout);
  97. int size = 128 << 20;
  98. char *p = (char*)malloc(size) + size;
  99. __asm__("movl %0, %%esp\n" :: "r"(p));
  100. memset(sig, 127/3, sizeof sig);
  101. scanf("%d%d", &n, &k);
  102. for (int i = 1; i < n; i++) {
  103. int u, v, d;
  104. scanf("%d%d%d", &u, &v, &d), u++, v++;
  105. push(u, v, d), push(v, u, d);
  106. }
  107. calc(1);
  108. if (pans < 2333333)
  109. cout << pans << endl;
  110. else puts("-1");
  111. return 0;
  112. }

bzoj2879: [Noi2012]美食节

学习了一个动态加边。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 40+80*100+5;
  4. struct node {
  5. int to, next, flow, cost, neg;
  6. } edge[MAXN*20];
  7. int head[MAXN], top = 0;
  8. void push(int i, int j, int f, int c)
  9. {
  10. // printf("%d--%d,%d-->%d\n", i, f, c, j);
  11. ++top, edge[top] = (node){j, head[i], f, c, top+1}, head[i] = top;
  12. ++top, edge[top] = (node){i, head[j], 0, -c, top-1}, head[j] = top;
  13. }
  14. int dis[MAXN], vis[MAXN], pre[MAXN], pre_edge[MAXN];
  15. queue<int> que;
  16. int S = MAXN-5, T = MAXN-4;
  17. int inf = 23333333;
  18. bool spfa(int &flow, int &cost)
  19. {
  20. memset(dis, 127/3, sizeof dis);
  21. memset(vis, 0, sizeof vis);
  22. vis[S] = 1, que.push(S), dis[S] = 0;
  23. while (!que.empty()) {
  24. int nd = que.front(); que.pop(); vis[nd] = 0;
  25. // cerr << nd << endl;
  26. for (int i = head[nd]; i; i = edge[i].next) {
  27. int to = edge[i].to, f = edge[i].flow, c = edge[i].cost;
  28. if (!f || dis[to] <= dis[nd]+c) continue;
  29. dis[to] = dis[nd]+c;
  30. pre[to] = nd, pre_edge[to] = i;
  31. if (!vis[to])
  32. vis[to] = 1, que.push(to);
  33. }
  34. }
  35. // cerr << dis[T] << endl;
  36. if (dis[T] > inf) return 0;
  37. int maxf = inf;
  38. for (int i = T; i != S; i = pre[i]) maxf = min(maxf, edge[pre_edge[i]].flow);
  39. for (int i = T; i != S; i = pre[i]) edge[pre_edge[i]].flow -= maxf, edge[edge[pre_edge[i]].neg].flow += maxf;
  40. flow += maxf, cost += maxf*dis[T];
  41. return 1;
  42. }
  43. int id[MAXN], k[MAXN], dish[MAXN], n, m;
  44. int top_tp = 0;
  45. int t[45][505], p[45];
  46. void mcf(int &flow, int &cost)
  47. {
  48. flow = cost = 0;
  49. while (spfa(flow, cost)) {
  50. int x = pre[T];
  51. // cerr << "id " << x << endl;
  52. x = id[x];
  53. k[x]++, id[++top_tp] = x;
  54. for (int i = 1; i <= n; i++)
  55. push(dish[i], top_tp, 1, k[x]*t[i][x]);
  56. push(top_tp, T, 1, 0);
  57. // printf("---%d\n", flow);
  58. }
  59. }
  60. int main()
  61. {
  62. scanf("%d%d", &n, &m);
  63. for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
  64. for (int i = 1; i <= n; i++)
  65. for (int j = 1; j <= m; j++)
  66. scanf("%d", &t[i][j]);
  67. for (int i = 1; i <= n; i++) dish[i] = ++top_tp;
  68. for (int i = 1; i <= n; i++) push(S, dish[i], p[i], 0);
  69. for (int i = 1; i <= m; i++) {
  70. id[++top_tp] = i, k[i]++;
  71. for (int j = 1; j <= n; j++)
  72. push(dish[j], top_tp, 1, k[i]*t[j][i]);
  73. push(top_tp, T, 1, 0);
  74. }
  75. int flow, cost;
  76. // puts("---");
  77. mcf(flow, cost);
  78. cout << cost << endl;
  79. return 0;
  80. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注