待补:
A (等我学完LCA)
B (未
C (未
哈哈,IOI赛制,老部分分选手 119/400 谢罪
4小时真的打吐了
先吐槽一波A,我47分和之前有个7分的代码就只是删了个注释,这时间卡的,(当然也有可能是我自己的常数太大,只能说还好不罚时不然我炸开
感觉很难取舍,第一眼看都没思路,于是几乎是一档一档打的,就导致后来看到x题xx分能出再去想再去做有点没时间(是非常没时间可恶
A 昔我往矣
正解LCA,树链剖分
快去学ye不能总靠队友,可恶
47分算法( q ≤ 100 q\leq 100 q≤100)
因为保证是一棵树,所以任意两点间的路径是唯一的,
五个点分别设为abcde,bfs a到其他四个点,把边不重复地加一下就好了,感觉常数可能有点大是卡评测姬过去的(大概
哦又试了一遍是47,好怪(
#include <bits/stdc++.h>
using namespace std;
const int N = 50010;
vector<int> g[N];
unordered_map<int, int> mp;
int mark[N], p[N];
bool vis[N],haveAdd[N];
int ans, n;
inline void bfs(int s) {
queue<int> que;
memset(vis, 0, sizeof vis);
memset(haveAdd, 0, sizeof haveAdd);
que.push(s);
vis[s] = 1;
while(!que.empty()) {
int tmp = que.front();
que.pop();
int siz = g[tmp].size();
for(int i = 0; i < siz; ++ i) {
int u = g[tmp][i];
if(vis[u]) continue;
vis[u] = 1;
p[u] = tmp;
if(mark[u]) {
//getPath(u);
int mn, mx;
int q = u;
while(1) {
//se.push_back(q);
mx = max(q, p[q]);
mn = min(q, p[q]);
ans += mp[mx * n + mn];
haveAdd[q] = 1;
q = p[q];
if(q == s) break;
if(haveAdd[q]) break;
}
}
que.push(u);
}
}
}
int main() {
scanf("%d", &n);
for(int i = 0, u, v, w; i < n - 1; ++ i) {
scanf("%d%d%d", &u, &v, &w);
g[u].push_back(v);
g[v].push_back(u);
int mn = min(u, v);
int mx = max(u, v);
mp[mx * n + mn] = w;
}
int q;
scanf("%d", &q);
while(q--) {
ans = 0;
int a, b, c, d, e;
scanf("%d%d%d%d%d", &a, &b, &c, &d, &e);
mark[b] = mark[c] = mark[d] = mark[e] = 1;
bfs(a);
printf("%d\n", ans);
mark[b] = mark[c] = mark[d] = mark[e] = 0;
}
}
B 杨柳依依
以每个点为起点做一遍 bfs,记录两两点对之间的最短路径长度和数量,可以通过。
待补
38分算法(是树)
因为保证是一棵树,所以任意两点间的路径是唯一的,
就暴力就行了
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
vector<int> g[N];
int cnt[N], v[N];
bool flag = 0;
void dfs(int p, int nw, int t, int idx) {
if(flag) return ;
v[idx] = nw;
if(nw == t) {
for(int i = 1; i <= idx; ++ i) {
cnt[v[i]] ++;
}
flag = 1;
return;
}
for(int i = 0; i < g[nw].size(); ++ i) {
int tmp = g[nw][i];
if(tmp == p) continue;
dfs(nw, tmp, t, idx + 1);
}
}
int main() {
int n, m;
cin >> n >> m;
for(int i = 0; i < m; ++ i) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
int k;
cin >> k;
for(int i = 0; i < k; ++ i) {
int s, t;
cin >> s >> t;
//memset(vis, 0, sizeof vis);
flag = 0;
dfs(-1, s, t, 1);
}
int mx = 0, ans = -1;
for(int i = 0; i <= n; ++ i) {
// cout << cnt[i] << " " ;
if(cnt[i] > mx) {
mx = cnt[i];
ans = i;
}
}
cout << ans << endl;
}
C 今我来思
23分
直接dfs所有可能性然后判断是否合法就行
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n , q;
int least[N], ans[N];
vector<int> g[N];
struct node{
int l, r, w;
}mp[N];
bool check() {
for(int i = 1;i <= q; ++ i) {
bool f = 0;
for(int j = mp[i].l; j <= mp[i].r; ++ j) {
if(ans[j] < mp[i].w) return 0;
if(ans[j] == mp[i].w) f = 1;
}
if(f == 0) return 0;
}
return 1;
}
int main() {
cin >> n >> q;
for(int i = 1; i <= q; ++ i) {
int l, r, w;
cin >> l >> r >> w;
mp[i].l = l; mp[i].r = r; mp[i].w = w;
for(int j = l; j <= r; ++ j) {
least[j] = max(least[j], w);
}
}
for(int i = 0; i < n; ++ i) {
g[least[i]].push_back(i);
}
bool f = 0;
int sum = 0;
for(int i = 0; i < n; ++ i) {
sum += g[i].size();
if(sum <= i) {
f = 1;
break;
}
}
if(f) {
for(int i = 1; i <= n; ++ i) {
cout << -1 << " ";
}
return 0;
}
int idx = 0;
for(int i = 0; i < n; ++ i) {
int siz = g[i].size();
for(int j = 0; j < siz; ++ j) {
ans[g[i][j]] = idx++;
}
}
if(!check()) {
for(int i = 1; i <= n; ++ i) {
cout << -1 << " ";
}
return 0;
}
for(int i = 0; i < n; ++ i) {
cout << ans[i] << " ";
}
return 0;
}
67分,
- 维护 0 ~ n − 1 每个数字可能出现范围 [ l , r ] ;
- 维护数组 a(即排列 p)中每个元素 $a_i $的最小值。
快结束的时候想冲67,然后因为真的没时间,就写了2,然后第一点卡住了,知道自己会错并且有在想怎么改但是没时间le,
D 雨雪霏霏
看了眼正解,好的不是我的题下一个(
快学莫队啊啊啊
11分暴力
#include <bits/stdc++.h>
using namespace std;
const int N = 50010;
int L[N][2], C[N][2];
bool vis[N];
int main() {
int r, c, q;
scanf("%d%d%d", &r, &c, &q);
for(int i = 1; i <= r; ++ i) {
for(int j = 1; j <= c; ++ j) {
scanf("%d", &L[j][i]);
}
}
for(int i = 1; i <= r; ++ i) {
for(int j = 1; j <= c; ++ j) {
scanf("%d", &C[j][i]);
}
}
int op, x, y, num;
while(q--) {
scanf("%d%d%d%d", &op, &x, &y, &num);
if(op == 1) {
C[x][y] = num;
}
else {
memset(vis, 0, sizeof vis);
if(num < L[x][y]) {
cout << 0 << endl;
continue;
}
int ans = 0;
num = min(num, c);
for(int i = num; i >= 1; --i) {
if(!vis[C[i][1]]) {
ans ++;
vis[C[i][1]] = 1;
}
}
printf("%d\n", ans);
}
}
}