2024.1.24 训练赛
A
一个比较经典的加权并查集,或者dfs也可以,没啥区别,主要是我忘了怎么写dfs了,第一时间想到的就是并查集,需要注意的事要路径压缩,居然忘了。。
核心代码可能就是找父亲和计算到父亲的距离了,其他真没啥了

#include<bits/stdc++.h> const int MAXN = 2e5 + 10; using namespace std; typedef long long LL; typedef pair<int, LL> P; int T; int n, m; int a, b; LL d; struct node { int fa; LL x; }; node k[MAXN]; P findfa(int x) { if(x != k[x].fa) { P res = findfa(k[x].fa); k[x].x += res.second; k[x].fa = res.first; } return {k[x].fa, k[x].x}; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>> T; while(T--) { cin>> n >> m; int flag = 1; for(int i = 1;i <= n;i++) k[i].fa = i, k[i].x = 0; for(int i = 1;i <= m;i++) { cin >> a >> b >> d; if(!flag) continue; if(d < 0) d = -d, swap(a, b); P f1 = findfa(a), f2 = findfa(b); if(f1.first == f2.first) { if(f2.second - f1.second == d) continue; else flag = 0; } else { k[f2.first].fa = f1.first; k[f2.first].x += d + f1.second - f2.second; } } // for(int i = 1;i <= n;i++) cout<<i<<" "<<k[i].fa<<" "<<k[i].x<<'\n'; if(flag) cout<<"YES\n"; else cout<<"NO\n"; } return 0; }
还有dfs写法,写放在这
我说这道题这么眼熟,以前写过
B
还好是相邻的交换,如果改成任意位置都可以交换就是另一种难度和做法了。
对于这道题很简单,其实就是求逆序对之和
边输入边处理就完事了,对于输入的每一个数,求在前面,出现的比他大的数之和,然后求出这些数的个数,乘以他自己就是要他到达正确位置需要花费的时间,用线段树和树状数组都可以做,但很明显树状数组更简单,但很明显我忘了还有树状数组这回事了。
问题:
1.人家只说奶牛个数和暴躁程度的范围相同,可从没说过每个奶牛的暴躁程度都不一样
2.四倍的空间居然爆了????奇怪。以后建议开八倍
C
这道题也蛮简单,只要二分可以连续摧毁的机器最大个数 mid 就好了
然后对一个连续的区间 l , l + mid - 1,判断这个区间内,每种细节的最大值之和是不是小于等于所给的 F 就好了
问题:
没有问题!一遍过
线段树越写越熟练了
#include<bits/stdc++.h> const int MAXN = 1e5 + 10; using namespace std; typedef long long LL; int n, m, k; struct node { int l, r; int a[6]; }t[MAXN << 3]; int p[MAXN][6]; LL ans[6], pr[6]; int flag; void build(int rt, int l, int r) { if(l == r) { t[rt].l = t[rt].r = l; for(int i = 1;i <= m;i++) t[rt].a[i] = p[l][i]; return ; } int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); t[rt].l = l; t[rt].r = r; for(int i = 1;i <= m;i++) t[rt].a[i] = max(t[rt<<1].a[i], t[rt<<1|1].a[i]); return ; } void query(int rt, int l, int r) { if(t[rt].l > r || t[rt].r < l) return ; if(t[rt].l >= l && t[rt].r <= r) { for(int i = 1;i <= m;i++) ans[i] = max(ans[i], (LL)t[rt].a[i]); return; } int mid = t[rt].l + t[rt].r >> 1; query(rt << 1, l, r); query(rt << 1 | 1, l, r); } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>> n >> m >> k; for(int i = 1;i <= n;i++) for(int j = 1;j <= m;j++) cin>> p[i][j]; build(1, 1, n); // for(int i = 1;i <= 6;i++){ // cout<< i << " " << t[i].l << " " << t[i].r<< " :"; // for(int j = 1;j <= m;j++) cout<< t[i].a[j] << " \n"[j==m]; // } int l = 0,r = n; LL res = 0; while(l <= r) { int mid = l + r >> 1; flag = 0; for(int i = 1;i <= n - mid + 1;i++) { res = 0; query(1, i, i + mid - 1); // cout<< i << " " << i + mid - 1 << " :"; for(int j = 1;j <= m;j++) res += ans[j]; if(res <= k) { flag = 1; for(int j = 1;j <= m;j++) pr[j] = ans[j]; break; } for(int j = 1;j <= m;j++) ans[j] = 0; } if(flag) l = mid + 1; else r = mid - 1; } // cout<< l <<" "<<r<<'\n'; for(int i = 1;i <= m;i++) cout<< pr[i] << " \n"[i==m]; return 0; }
D
没啥难的,只需要知道从后往前找,让每次修改的范围不断变大就可以了。就是打印输出我感觉有点绕
我是先从小到大排序,然后用两个区间卡住还没打印的区域,如果是要求升序,那就从 r 开始数,如果降序就从 l, 然后更新 l 或者 r 就好了。赛时怎么没想到。
#include<bits/stdc++.h> const int MAXN = 2e5 + 10; using namespace std; int n, m; int op, r; int k[MAXN]; int kk[MAXN]; struct node { int op; int r; }; pair <int, int> ord[MAXN]; int cnt2; node q[MAXN], p[MAXN]; int cnt; bool cmp1(int a, int b){return a < b;} bool cmp2(int a, int b){return a > b;} int main() { ios::sync_with_stdio(false); cin.tie(0); cin>> n >> m; for(int i = 1;i <= n;i++) cin>> k[i], kk[i] = k[i]; for(int i = 1;i <= m;i++) cin>> p[i].op >> p[i].r; for(int i = m;i;i--) { if(p[i].r > q[cnt].r) q[++cnt] = p[i]; } sort(k + 1, k + q[cnt].r + 1, cmp1); ord[++cnt2].first = q[cnt].r + 1; ord[cnt2].second = n; q[0].r = 0; int l = 1, r = q[cnt].r; // for(int i = cnt;i;i--) cout<< q[i].op << " " << q[i].r << '\n'; for(int i = cnt;i;i--) { int len = q[i].r - q[i - 1].r; if(q[i].op == 1) ord[++cnt2].first = r - len + 1, ord[cnt2].second = r, r -= len; else ord[++cnt2].first = l + len - 1, ord[cnt2].second = l, l += len; } for(int i = cnt2;i;i--) { int a = ord[i].first, b = ord[i].second; if(a > n || b > n) continue; // cout << a << " " << b << ":"; if(a < b) for(int j = a;j <= b;j++) cout<<k[j]<<" "; else for(int j = a;j >= b;j--) cout<<k[j]<<' '; // cout << '\n'; } return 0; }

浙公网安备 33010602011771号