https://vjudge.net/contest/173780
A.假设 Pt = i,则由Ppi = i得
Ppt = t = Pi
所以就有 if Pt = i then Pi = t
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 int n, a[110]; 7 8 int main() { 9 scanf("%d", &n); 10 if(n & 1) puts("-1"); 11 else { 12 for(int i = 1;i <= n;i ++) 13 a[i] = i; 14 for(int i = 1;i <= n;i += 2) 15 swap(a[i], a[i + 1]); 16 for(int i = 1;i <= n;i ++) 17 printf("%d ", a[i]); 18 } 19 }
B.
C.treap练手题,STL_set练手题,链表练手题
set用的不熟所以直接上的链表
排序后时间倒序来看的思路
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 typedef long long ll; 7 8 const int maxn = 50010; 9 10 int n, b[maxn]; 11 12 ll ans; 13 14 struct List{ 15 int next, last; 16 }c[maxn]; 17 18 struct node{ 19 ll x; 20 int y; 21 bool operator < (const node &a) const { 22 return x < a.x; 23 } 24 }a[maxn]; 25 26 int main() { 27 scanf("%d", &n); 28 for(int i = 1;i <= n;i ++) 29 scanf("%lld", &a[i].x), a[i].y = i; 30 ans = a[1].x; 31 a[0].x = -1000000000000ll; 32 a[n + 1].x = 1000000000000ll; 33 sort(a + 1, a + n + 1); 34 for(int i = 1;i <= n;i ++) b[a[i].y] = i; 35 for(int i = 1;i <= n;i ++) { 36 c[i].next = i + 1; 37 c[i].last = i - 1; 38 } 39 for(int i = n;i > 1;i --) { 40 ans += min(a[b[i]].x - a[c[b[i]].last].x, a[c[b[i]].next].x - a[b[i]].x); 41 c[c[b[i]].last].next = c[b[i]].next; 42 c[c[b[i]].next].last = c[b[i]].last; 43 } 44 printf("%lld ", ans); 45 return 0; 46 }
D.边权给点,点修改和路径查询
直接上树剖+线段树,考场写狗
多组数据需要clear存边的vector,fa 和 son
修改的时候bel[i]找到第 i 条边权给的点
还要对应该点在线段树上的叶节点位置!
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn = 10010; 8 9 int Case, n, M; 10 11 struct Edge{ 12 int v, w, num; 13 }; 14 15 vector <Edge> edge[maxn]; 16 17 char str[10]; 18 19 int a, b, tr[maxn << 2]; 20 21 int bel[maxn], siz[maxn], son[maxn], val[maxn]; 22 23 int cnt, fa[maxn], dep[maxn], pos[maxn], dfn[maxn], top[maxn]; 24 25 void dfs1(int u) { 26 siz[u] = 1; 27 for(int v, i = 0;i < edge[u].size();i ++) { 28 v = edge[u][i].v; 29 if(v == fa[u]) continue; 30 fa[v] = u; 31 dep[v] = dep[u] + 1; 32 val[v] = edge[u][i].w; 33 bel[edge[u][i].num] = v; 34 dfs1(v), siz[u] += siz[v]; 35 if(siz[son[u]] < siz[v]) son[u] = v; 36 } 37 } 38 39 void dfs2(int u, int tp) { 40 top[u] = tp, pos[u] = ++ cnt, dfn[cnt] = u; 41 if(son[u]) dfs2(son[u], tp); 42 for(int v, i = 0;i < edge[u].size();i ++) { 43 v = edge[u][i].v; 44 if(v != fa[u] && v != son[u]) 45 dfs2(v, v); 46 } 47 } 48 49 void change(int i, int x) { 50 i = pos[i]; 51 for(tr[i += M] = x, i >>= 1;i;i >>= 1) 52 tr[i] = max(tr[i << 1], tr[i << 1 | 1]); 53 } 54 55 int mmax(int s, int t) { 56 int res = -666666666; 57 for(s += M - 1, t += M + 1;s ^ t ^ 1;s >>= 1, t >>= 1) { 58 if(~ s & 1) res = max(res, tr[s ^ 1]); 59 if( t & 1) res = max(res, tr[t ^ 1]); 60 } 61 return res; 62 } 63 64 void query(int u, int v) { 65 int fu = top[u], fv = top[v], res = -666666666; 66 while(fu != fv) { 67 if(dep[fu] < dep[fv]) swap(u, v), swap(fu, fv); 68 res = max(res, mmax(pos[fu], pos[u])); 69 u = fa[fu], fu = top[u]; 70 } 71 if(u == v) printf("%d ", res); 72 else { 73 if(dep[u] < dep[v]) swap(u, v); 74 printf("%d ", max(res, mmax(pos[v] + 1, pos[u]))); 75 } 76 } 77 78 int main() { 79 //freopen("test.txt","r",stdin); 80 val[1] = -666666666; 81 int u, v, w; 82 scanf("%d", &Case); 83 while(Case --) { 84 cnt = 0; 85 scanf("%d", &n); 86 for(int i = 1;i <= n;i ++) edge[i].clear(), fa[i] = son[i] = 0; 87 for(int i = 1;i < n;i ++) { 88 scanf("%d %d %d", &u, &v, &w); 89 edge[u].push_back((Edge){v, w, i}); 90 edge[v].push_back((Edge){u, w, i}); 91 } 92 dfs1(1), dfs2(1, 1); 93 for(M = 1;M < n + 2; M <<= 1); 94 for(int i = 1;i <= n;i ++) tr[i + M] = val[dfn[i]]; 95 for(int i = n + 1;i <= M + 1;i ++) tr[i + M] = val[1]; 96 for(int i = M;i;i --) tr[i] = max(tr[i << 1], tr[i << 1 | 1]); 97 while(scanf("%s", str), str[0] != 'D') { 98 if(str[0] == 'C') scanf("%d %d", &a, &b), change(bel[a], b); 99 else scanf("%d %d", &a, &b), query(a, b); 100 } 101 puts(""); 102 } 103 }
E.考场上脑补出来一个正解,可惜只差了一步
两个单调队列,一增一减,从前向后扫
当扫到某个位置,最大差距 > R 时
踢出两个队列中位置最靠前的元素直至差距 <= R
如果这是最大差距 >= L 则更新答案即可
时间复杂度O(n),别人说这是个做过的RMQ啊...
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int maxn = 100010; 7 8 int n, x, y, m, a[maxn], q1[maxn], q2[maxn]; 9 10 int l1, r1, l2, r2, t; 11 12 int main() { 13 while(scanf("%d %d %d", &n, &x, &y) != EOF) { 14 for(int i = 1;i <= n;i ++) 15 scanf("%d", &a[i]); 16 m = t = 0, l1 = l2 = 1, r1 = r2 = 0; 17 for(int i = 1;i <= n;i ++) { 18 while(l1 <= r1 && a[i] > a[q1[r1]]) r1 --; 19 q1[++ r1] = i; 20 while(l2 <= r2 && a[i] < a[q2[r2]]) r2 --; 21 q2[++ r2] = i; 22 while(l1 <= r1 && l2 <= r2 && a[q1[l1]] > a[q2[l2]] + y) { 23 if(q1[l1] < q2[l2]) t = q1[l1 ++]; 24 else t = q2[l2 ++]; 25 } 26 if(l1 <= r1 && l2 <= r2 && a[q1[l1]] >= a[q2[l2]] + x) m = max(m, i - t); 27 } 28 printf("%d ", m); 29 } 30 return 0; 31 }
F.就是枚举min,然后单调队列求出左右拓展多远就好了
1 #include <cstdio> 2 3 const int maxn = 100010; 4 5 int l = 1, r, q[maxn]; 6 7 int L, R, n, a[maxn], b[maxn], c[maxn]; 8 9 long long ans = -1, tmp, s[maxn]; 10 11 int main() { 12 scanf("%d", &n); 13 for(int i = 1;i <= n;i ++) 14 scanf("%d", &a[i]), s[i] = a[i] + s[i - 1]; 15 for(int i = 1;i <= n;i ++) { 16 while(l <= r && a[i] < a[q[r]]) b[q[r]] = i - q[r], r --; 17 q[++ r] = i; 18 } 19 while(l <= r) b[q[r]] = n + 1 - q[r], r --; 20 l = 1, r = 0; 21 for(int i = n;i;i --) { 22 while(l <= r && a[i] < a[q[r]]) c[q[r]] = q[r] - i, r --; 23 q[++ r] = i; 24 } 25 while(l <= r) c[q[r]] = q[r], r --; 26 for(int i = 1;i <= n;i ++) { 27 tmp = (s[i + b[i] - 1] - s[i - c[i]]) * a[i]; 28 if(tmp > ans) ans = tmp, L = i - c[i] + 1, R = i + b[i] - 1; 29 } 30 printf("%lld %d %d", ans, L ,R); 31 return 0; 32 }
G.开始没看清题发现大家都会写区间众数?
连续的相同...线段树傻逼题
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int maxn = 100010; 7 8 struct node{ 9 int ls, rs, lc, rc, mm; 10 }tr[maxn << 2]; 11 12 int n, m, c[maxn]; 13 14 node operator +(const node &a, const node &b) { 15 node res; 16 res.ls = a.ls; 17 res.lc = a.lc; 18 res.rs = b.rs; 19 res.rc = b.rc; 20 res.mm = max(a.mm, b.mm); 21 if(a.rc == b.lc) { 22 res.mm = max(res.mm, a.rs + b.ls); 23 if(a.lc == a.rc) res.ls += b.ls; 24 if(b.lc == b.rc) res.rs += a.rs; 25 } 26 return res; 27 } 28 29 void build(int o, int l, int r) { 30 if(l == r) { 31 tr[o] = (node){1, 1, c[r], c[r], 1}; 32 return; 33 } 34 int mid = (l + r) >> 1; 35 build(o << 1, l, mid); 36 build(o << 1 | 1, mid + 1, r); 37 tr[o] = tr[o << 1] + tr[o << 1 | 1]; 38 } 39 40 node ask(int o, int l, int r, int s, int t){ 41 if(s <= l && r <= t) return tr[o]; 42 int mid = (l + r) >> 1; 43 if(t <= mid) return ask(o << 1, l, mid, s, t); 44 else if(s > mid) return ask(o << 1 | 1, mid + 1, r, s, t); 45 else return ask(o << 1, l, mid, s, t) + ask(o << 1 | 1, mid + 1, r, s, t); 46 } 47 48 int main() { 49 int a, b; 50 while(scanf("%d %d", &n, &m), n != 0) { 51 for(int i = 1;i <= n;i ++) 52 scanf("%d", &c[i]); 53 build(1, 1, n); 54 //printf("%d %d %d ",tr[1].mm,tr[6].rc, tr[7].lc); 55 while(m --) { 56 scanf("%d %d", &a, &b); 57 printf("%d ", ask(1, 1, n, a, b).mm); 58 } 59 } 60 }
H.
I.无修改查询树上路径和,随便做啦
dis[u] + dis[v] - dis[lca] * 2
我直接上的bfs树剖求lca
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn = 40010; 8 9 struct Edge{ 10 int v, w; 11 }; 12 13 vector <Edge> edge[maxn]; 14 15 int Case, n, m, a, b, c, dis[maxn]; 16 17 int l, r, q[maxn], siz[maxn], son[maxn]; 18 19 int cnt, fa[maxn], dep[maxn], top[maxn]; 20 21 int lca(int u, int v) { 22 int fu = top[u], fv = top[v]; 23 while(fu != fv) { 24 if(dep[fu] < dep[fv]) swap(u, v), swap(fu, fv); 25 u = fa[fu], fu = top[u]; 26 } 27 return dep[u] < dep[v] ? u : v; 28 } 29 30 int main() { 31 int u, v, w; 32 scanf("%d", &Case); 33 while(Case --) { 34 scanf("%d %d", &n, &m); 35 for(int i = 1;i < n;i ++) { 36 scanf("%d %d %d", &u, &v, &w); 37 edge[u].push_back((Edge){v, w}); 38 edge[v].push_back((Edge){u, w}); 39 } 40 l = r = 0, q[++ r] = 1; 41 while(l <= r) { 42 u = q[l ++]; 43 siz[u] = 1, son[u] = top[u] = 0; 44 for(int i = 0;i < edge[u].size();i ++) { 45 v = edge[u][i].v; 46 if(v == fa[u]) continue; 47 fa[v] = u, q[++ r] = v, dep[v] = dep[u] + 1, dis[v] = dis[u] + edge[u][i].w; 48 } 49 } 50 for(int i = n;i > 1;i --) { 51 siz[fa[q[i]]] += siz[q[i]]; 52 if(!son[fa[q[i]]] || siz[son[fa[q[i]]]] < siz[q[i]]) son[fa[q[i]]] = q[i]; 53 } 54 for(int i = 1;i <= n;i ++) { 55 u = q[i]; 56 if(son[fa[u]] == u) top[u] = top[fa[u]]; 57 else top[u] = u; 58 } 59 while(m --) { 60 scanf("%d %d", &a, &b); 61 c = lca(a, b); 62 printf("%d ", dis[a] - dis[c] - dis[c] + dis[b]); 63 } 64 } 65 }
J.裸树状数组
1 #include <cstdio> 2 3 const int maxn = 50010; 4 5 int c[maxn], a[maxn]; 6 7 int Case, n, x, y; 8 9 char str[10]; 10 11 int lowbit(int x) { 12 return (x & (-x)); 13 } 14 15 int ask(int i) { 16 int res = 0; 17 while(i > 0) res += c[i], i -= lowbit(i); 18 return res; 19 } 20 21 void add(int i, int x) { 22 while(i <= n) c[i] += x, i += lowbit(i); 23 } 24 25 26 int main() { 27 //freopen("test.txt", "r", stdin); 28 scanf("%d", &Case); 29 for(int tt = 1;tt <= Case;tt ++) { 30 printf("Case %d: ", tt); 31 scanf("%d", &n); 32 for(int i = 1;i <= n;i ++) 33 scanf("%d", &a[i]), a[i] += a[i - 1]; 34 while(scanf("%s", str), str[0] != 'E') { 35 scanf("%d %d", &x, &y); 36 if(str[0] == 'Q') printf("%d ", ask(y) - ask(x - 1) + a[y] - a[x - 1]); 37 else add(x, y * (str[0] == 'A' ? 1 : -1)); 38 } 39 for(int i = 1;i <= n;i ++) c[i] = 0; 40 } 41 return 0; 42 }
K.区间加和区间求和,差分树状数组除非有封装好的板子
不然现场还是只能写线段树
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 typedef long long ll; 7 8 const int maxn = 100010; 9 10 int n, m, d[maxn]; 11 12 char str[10]; 13 14 int a, b, c; 15 16 ll s[maxn]; 17 18 struct node{ 19 ll lazy, sum; 20 }tr[maxn << 2]; 21 22 void pushup(int o) { 23 tr[o].sum = tr[o << 1].sum + tr[o << 1 | 1].sum; 24 } 25 26 void pushdown(int o, int l, int r) { 27 if(!tr[o].lazy) return; 28 int mid = (l + r) >> 1; 29 tr[o << 1].sum += tr[o].lazy * (mid - l + 1); 30 tr[o << 1 | 1].sum += tr[o].lazy * (r - mid); 31 tr[o << 1].lazy += tr[o].lazy; 32 tr[o << 1 |1].lazy += tr[o].lazy; 33 tr[o].lazy = 0; 34 } 35 36 void add(int o, int l, int r, int s, int t, int x) { 37 if(l != r) pushdown(o, l, r); 38 if(s <= l && r <= t) { 39 tr[o].lazy += x; 40 tr[o].sum += 1ll * x * (r - l + 1); 41 return; 42 } 43 int mid = (l + r) >> 1; 44 if(s <= mid) add(o << 1, l, mid, s, t, x); 45 if(mid < t) add(o << 1 | 1, mid + 1, r, s, t, x); 46 pushup(o); 47 } 48 49 ll query(int o, int l, int r, int s, int t) { 50 if(l != r) pushdown(o, l, r); 51 if(s <= l && r <= t) return tr[o].sum; 52 ll res = 0; 53 int mid = (l + r) >> 1; 54 if(s <= mid) res += query(o << 1, l, mid, s, t); 55 if(mid < t) res += query(o << 1 | 1, mid + 1, r, s, t); 56 pushup(o); 57 return res; 58 } 59 60 int main(int argc, char const *argv[]){ 61 scanf("%d %d", &n, &m); 62 for(int i = 1;i <= n;i ++) 63 scanf("%d", &d[i]), s[i] = s[i - 1] + d[i]; 64 while(m --) { 65 scanf("%s %d %d", str, &a, &b); 66 if(str[0] == 'Q') printf("%lld ", query(1, 1, n, a, b) + s[b] - s[a - 1]); 67 else scanf("%d", &c), add(1, 1, n, a, b, c); 68 } 69 return 0; 70 }
L.vector会TLE改邻接表能过...***
dfs序 + 树状数组
1 #include <cstdio> 2 3 const int maxn = 200010; 4 5 int n, m, q, a[maxn], c[maxn], st[maxn], en[maxn]; 6 7 int tot, head[maxn], to[maxn], next[maxn]; 8 9 void ade(int x, int y) { 10 to[++ tot] = y, next[tot] = head[x], head[x] = tot; 11 } 12 13 int lowbit(int x) { 14 return (x & (-x)); 15 } 16 17 int ask(int i) { 18 int res = 0; 19 while(i > 0) res += c[i], i -= lowbit(i); 20 return res; 21 } 22 23 void add(int i, int x) { 24 while(i <= n) c[i] += x, i += lowbit(i); 25 } 26 27 void dfs(int x, int f) { 28 a[x] = 1, st[x] = ++ m; 29 for(int y, i = head[x];i;i = next[i]) { 30 y = to[i]; 31 if(y == f) continue; 32 dfs(y, x); 33 } 34 en[x] = m; 35 } 36 37 char str[10]; 38 39 int x; 40 41 int main() { 42 scanf("%d", &n); 43 for(int u, v, i = 1;i < n;i ++) { 44 scanf("%d %d", &u, &v); 45 ade(u, v), ade(v, u); 46 } 47 dfs(1, 1); 48 scanf("%d", &q); 49 while(q --) { 50 scanf("%s %d", str, &x); 51 if(str[0] == 'Q') printf("%d ", ask(en[x]) - ask(st[x] - 1) + en[x] - st[x] + 1); 52 else { 53 if(a[x]) add(st[x], -1), a[x] = 0; 54 else add(st[x], 1), a[x] = 1; 55 } 56 } 57 return 0; 58 }