题解
第一题:水
#include<bits/stdc++.h> using namespace std; const int M = 1e5 + 5; struct Node{ int s, t; }p[M]; bool cmp(Node A, Node B){ return A.t > B.t; } int main(){ freopen("manage.in","r",stdin); freopen("manage.out","w",stdout); int n; scanf("%d", &n); for(int i = 1; i <= n; i++)scanf("%d%d", &p[i].s, &p[i].t); sort(p + 1, p + 1 + n, cmp); int now = p[1].t; p[n + 1].t = 1e9; for(int i = 1; i <= n; i++){ now -= p[i].s; if(now > p[i + 1].t) now = p[i + 1].t; } printf("%d ", now >= 0 ? now : -1); }
第二题:先tarjan缩点,然后树上背包;我用的带权并查集,跑的分组背包,忽略了分叉的情况;
#include<bits/stdc++.h> using namespace std; const int M = 1e5 + 10; int v[M], w[M], V[M], W[M], fa[M], dp[305][M], idx, scc; int tot, place[M], h[M], dfn[M], low[M], d[M], siz[M], du[M]; bool ins[M]; struct edge{ int v, nxt; }G[M]; void add(int u, int v){ G[++tot].nxt = h[u]; G[tot].v = v; h[u] = tot; } vector <int> group[M]; stack <int> t; void tarjan(int u){ dfn[u] = low[u] = ++idx; t.push(u); ins[u] = 1; int v = d[u]; if(v){ if(!dfn[v]){ tarjan(v); low[u] = min(low[u], low[v]); } else if(ins[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]){ scc++; while(1){ int st = t.top(); t.pop(); place[st] = scc; ins[st] = 0; if(st == u)break; } } } int n, m; void dfs(int u){ dp[u][W[u]] = V[u]; for(int i = h[u]; i; i = G[i].nxt){ int v = G[i].v; dfs(v); for(int vv = m; vv >= W[u]; vv--) for(int p = 0; p <= vv; p++) if(dp[u][vv - p] >= 0 && dp[v][p] >= 0) dp[u][vv] = max(dp[u][vv], dp[u][vv - p] + dp[v][p]); } } int main(){ freopen("software.in","r",stdin); freopen("software.out","w",stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) scanf("%d", &w[i]); for(int i = 1; i <= n; i++) scanf("%d", &v[i]); for(int i = 1; i <= n; i++) scanf("%d", &d[i]); for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); for(int i = 1; i <= n; i++){ int u = place[i]; V[u] += v[i]; W[u] += w[i]; if(place[d[i]] != place[i]) add(place[d[i]], place[i]), du[place[i]]++; } for(int i = 1; i <= scc; i++) if(!du[i])add(0, i); memset(dp, 0x8f, sizeof(dp)); dfs(0); int ans = 0; for(int i = 0; i <= m; i++)ans = max(ans, dp[0][i]); printf("%d ", ans); }
第三题:线段统计区间中递增的数, modify的神奇操作;
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n,val,pos,m; struct nd { double val; int ans; }f[4 * N]; int calc(int o,int l,int r,double val) { if(l == r) return f[o].val - val >= 1e-10; int mid = (l + r) >> 1; if(f[2 * o].val - val <= 1e-10) { return calc(2 * o + 1,mid + 1,r,val); } else { return f[o].ans - f[2 * o].ans + calc(2 * o,l,mid,val); } } void modify(int o,int l,int r,int pos,double val) { if(l == r) { f[o].val = val; f[o].ans = 1; return ; } int mid = (l + r) >> 1; if(pos <= mid) modify(2 * o,l,mid,pos,val); else modify(2 * o + 1,mid + 1,r,pos,val); f[o].val = max(f[2 * o].val,f[2 * o + 1].val); f[o].ans = f[2 * o].ans + calc(2 * o + 1,mid + 1,r,f[2 * o].val); } int main( ) { freopen("rebuild.in","r",stdin); freopen("rebuild.out","w",stdout); scanf("%d%d",& n,& m); while(m --) { scanf("%d%d",& pos,& val); modify(1,1,n,pos,1.0*val/pos); printf("%d ", f[1].ans); } }