2018 Multi-University Training Contest 7
Contents
A. Age of Moyu
题意:
给出一张图,从
思路:
用 set 记录有当前点的最小花费有多少种方案到达,然后最短路。
Code
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 10;
struct Edge {
int to, nxt, val;
Edge() {}
Edge(int to, int nxt, int val) : to(to), nxt(nxt), val(val){};
} edge[maxn << 1];
set<int> s[maxn];
int head[maxn], tot;
void Init(int n) {
for (int i = 0; i <= n; ++i) head[i] = -1, s[i].clear();
tot = 0;
}
void addedge(int u, int v, int val) {
edge[tot] = Edge(v, head[u], val);
head[u] = tot++;
}
struct qnode {
int v, c;
int pre;
int fa;
qnode() {}
qnode(int v, int c, int pre, int fa) : v(v), c(c), pre(pre), fa(fa) {}
bool operator<(const qnode &r) const {
return c > r.c;
}
};
int n, m;
int dist[maxn];
void BFS(int st) {
for (int i = 1; i <= n; ++i) dist[i] = INF;
priority_queue<qnode> q;
dist[st] = 0;
q.push(qnode(st, 0, 0, 0));
while (!q.empty()) {
qnode tmp = q.top();
q.pop();
int u = tmp.v;
if (tmp.c > dist[u])
continue;
else if (tmp.c == dist[u]) {
if (s[u].find(tmp.pre) != s[u].end())
continue;
s[u].insert(tmp.pre);
} else {
dist[u] = tmp.c;
s[u].clear();
s[u].insert(tmp.pre);
}
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
int cost = edge[i].val;
if (v == tmp.fa)
continue;
if (dist[u] + (cost != tmp.pre) <= dist[v]) {
dist[v] = dist[u] + (cost != tmp.pre);
if (v != n) {
q.push(qnode(v, dist[v], cost, u));
}
}
}
}
}
int main() {
int t;
while (scanf("%d %d", &n, &m) != EOF) {
Init(n);
for (int i = 1; i <= m; ++i) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
BFS(1);
if (dist[n] == INF)
dist[n] = -1;
printf("%d\n", dist[n]);
}
return 0;
}
B. AraBellaC
留坑。
C. YJJ’s Stack
留坑。
D. Go to school
留坑。
E. GuGuFishtion
留坑。
F. Lord Li's problem
留坑。
G. Reverse Game
留坑。
H. Traffic Network in Numazu
题意:
两种操作:
- 第一种是更改一条边权的值。
- 第二种是查询
的最短路径。
给出的是一颗树加一条边。
思路:
将形成环的边单独拿出来考虑。
那么考虑是否经过这条边使得答案更优。
修改操作用线段树或者树状数组维护。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const int DEG = 20;
struct EDGE {
int u, v, w;
} EDGE[maxn], TEMP;
struct Edge {
int to, nxt, val;
Edge() {}
Edge(int to, int nxt, int val) : to(to), nxt(nxt), val(val) {}
} edge[maxn << 1];
int head[maxn], tot, cnt;
int father[maxn];
void Init(int n) {
for (int i = 0; i <= n; ++i) head[i] = -1, father[i] = i;
tot = cnt = 0;
}
int find(int x) {
return x == father[x] ? father[x] : father[x] = find(father[x]);
}
void mix(int x, int y) {
x = find(x), y = find(y);
if (x != y)
father[x] = y;
}
bool same(int x, int y) {
return find(x) == find(y);
}
void addedge(int u, int v, int val) {
edge[tot] = Edge(v, head[u], val);
head[u] = tot++;
}
int dro[maxn];
int ord[maxn], son[maxn];
int fa[maxn][DEG];
int deg[maxn];
void DFS(int u, int pre) {
ord[u] = ++cnt;
dro[cnt] = u;
for (int i = 1; i < DEG; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if (v == pre)
continue;
fa[v][0] = u;
deg[v] = deg[u] + 1;
DFS(v, u);
}
son[u] = cnt;
}
int LCA(int u, int v) {
if (deg[u] > deg[v])
swap(u, v);
int hu = deg[u], hv = deg[v];
int tu = u, tv = v;
for (int det = hv - hu, i = 0; det; det >>= 1, ++i) {
if (det & 1) {
tv = fa[tv][i];
}
}
if (tu == tv)
return tu;
for (int i = DEG - 1; i >= 0; --i) {
if (fa[tu][i] == fa[tv][i])
continue;
tu = fa[tu][i];
tv = fa[tv][i];
}
return fa[tu][0];
}
struct node {
int l, r;
ll val, lazy;
node() {}
node(int l, int r, ll val, ll lazy) : l(l), r(r), val(val), lazy(lazy) {}
} tree[maxn << 2];
void pushup(int id) {
tree[id].val = tree[id << 1].val + tree[id << 1 | 1].val;
}
void pushdown(int id) {
if (tree[id].lazy) {
ll lazy = tree[id].lazy;
tree[id << 1].val += lazy;
tree[id << 1 | 1].val += lazy;
tree[id << 1].lazy += lazy;
tree[id << 1 | 1].lazy += lazy;
tree[id].lazy = 0;
}
}
void build(int id, int l, int r) {
tree[id] = node(l, r, 0, 0);
if (l == r)
return;
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
}
void update(int id, int l, int r, ll val) {
if (l <= tree[id].l && r >= tree[id].r) {
tree[id].val += val;
tree[id].lazy += val;
return;
}
pushdown(id);
int mid = (tree[id].l + tree[id].r) >> 1;
if (mid >= l)
update(id << 1, l, r, val);
if (r > mid)
update(id << 1 | 1, l, r, val);
pushup(id);
}
ll query(int id, int pos) {
if (tree[id].l == pos && tree[id].r == pos) {
return tree[id].val;
}
pushdown(id);
int mid = (tree[id].l + tree[id].r) >> 1;
if (pos <= mid)
return query(id << 1, pos);
if (pos > mid)
return query(id << 1 | 1, pos);
pushup(id);
}
ll getdis(int u, int v) {
int root = LCA(u, v);
return query(1, ord[u]) + query(1, ord[v]) - 2 * query(1, ord[root]);
}
int n, q;
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d %d", &n, &q);
Init(n);
for (int i = 1; i <= n; ++i) {
scanf("%d %d %d", &EDGE[i].u, &EDGE[i].v, &EDGE[i].w);
int u = EDGE[i].u, v = EDGE[i].v, w = EDGE[i].w;
if (same(u, v)) {
TEMP = EDGE[i];
continue;
}
mix(u, v);
addedge(u, v, w);
addedge(v, u, w);
}
fa[1][0] = 1;
deg[1] = 0;
DFS(1, -1);
build(1, 1, n);
for (int i = 1; i <= n; ++i) {
int u = EDGE[i].u, v = EDGE[i].v, w = EDGE[i].w;
if (u == TEMP.u && v == TEMP.v)
continue;
if (fa[u][0] == v) {
update(1, ord[u], son[u], w);
} else if (fa[v][0] == u)
;
{ update(1, ord[v], son[v], w); }
}
// for(int i = 1; i <= n; ++i) cout << ord[i] << endl;
// for(int i = 1; i <= n; ++i) cout << i << " " << query(1, ord[i]) << endl;
while (q--) {
int op, x, y;
scanf("%d %d %d", &op, &x, &y);
if (op == 0) {
int u = EDGE[x].u, v = EDGE[x].v, w = EDGE[x].w;
if (u == TEMP.u && v == TEMP.v) {
EDGE[x].w = y;
TEMP.w = y;
}
if (fa[u][0] == v) {
update(1, ord[u], son[u], y - w);
} else if (fa[v][0] == u) {
update(1, ord[v], son[v], y - w);
}
EDGE[x].w = y;
} else if (op == 1) {
ll ans = getdis(x, y);
ans = min(ans, getdis(x, TEMP.u) + TEMP.w + getdis(y, TEMP.v));
ans = min(ans, getdis(y, TEMP.u) + TEMP.w + getdis(x, TEMP.v));
printf("%lld\n", ans);
}
}
}
return 0;
}
I. Tree
题意:
一棵树种,每个点有一个权值,表示可以向上跳几步,两种操作,一种是修改某点权值,还有一种是询问某个点需要跳几次跳出。
思路:
DFS 序分块,弹飞绵阳升级版,注意更新的时候,维护一个
Code
#include <bits/stdc++.h>
using namespace std;
namespace FastIO {
#define BUF_SIZE 10000005
bool IOerror = false;
inline char NC() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = true;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
template <typename T>
inline void read(T &x) {
char ch;
while (blank(ch = NC()))
;
if (IOerror) {
x = -1;
return;
}
bool flag = false;
if (ch == '-') {
flag = true;
ch = NC();
}
if (!isdigit(ch))
while (!isdigit(ch = NC()))
;
for (x = ch - '0'; isdigit(ch = NC()); x = x * 10 + ch - '0')
;
if (flag)
x *= -1;
}
void out(int x) {
if (x / 10)
out(x / 10);
putchar(x % 10 + '0');
}
inline void print(int x) {
out(x);
puts("");
}
#undef BUF_SIZE
} // namespace FastIO
using namespace FastIO;
#define N 100010
#define DEG 20
#define block 400
int t, n, q;
int a[N], b[N], In[N], Out[N], fa[N][20], deep[N], p[N], fp[N], cnt;
vector<int> G[N];
void Init() {
for (int i = 1; i <= n; ++i) G[i].clear();
cnt = 0;
fa[1][0] = 1;
deep[1] = 0;
}
void DFS(int u) {
p[u] = ++cnt;
fp[cnt] = u;
for (int i = 1; i < DEG; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (auto v : G[u])
if (v != fa[u][0]) {
deep[v] = deep[u] + 1;
DFS(v);
}
}
int GetK(int x, int k) {
bitset<20> b;
b = k;
for (int i = 19; i >= 0; --i)
if (b[i])
x = fa[x][i];
return x;
}
int query(int x) {
int res = 0;
x = p[x];
while (x) {
res += b[x];
x = Out[x];
}
return res;
}
void update(int x) {
if (a[x] > deep[x]) {
b[p[x]] = 1;
Out[p[x]] = 0;
In[p[x]] = p[x];
} else {
int root = GetK(x, a[x]);
if ((p[root] - 1) / block != (p[x] - 1) / block) {
b[p[x]] = 1;
Out[p[x]] = p[root];
In[p[x]] = p[x];
} else {
b[p[x]] = b[p[root]] + 1;
Out[p[x]] = Out[p[root]];
In[p[x]] = p[root];
}
}
x = p[x];
for (int i = x + 1; i <= n && (i - 1) / block == (x - 1) / block; ++i) {
if (In[i] != i) {
b[i] = b[In[i]] + 1;
Out[i] = Out[In[i]];
}
}
}
void Run() {
read(t);
while (t--) {
read(n);
Init();
for (int i = 2; i <= n; ++i) {
read(fa[i][0]);
G[fa[i][0]].push_back(i);
}
DFS(1);
for (int i = 1; i <= n; ++i) read(a[i]);
for (int i = 1; i <= n; ++i) {
int x = fp[i];
if (a[x] > deep[x]) {
b[i] = 1;
Out[i] = 0;
In[i] = i;
continue;
}
int root = GetK(x, a[x]);
if ((p[root] - 1) / block != (i - 1) / block) {
b[i] = 1;
Out[i] = p[root];
In[i] = i;
} else {
b[i] = b[p[root]] + 1;
Out[i] = Out[p[root]];
In[i] = p[root];
}
}
read(q);
for (int i = 1, op, x, v; i <= q; ++i) {
read(op);
read(x);
if (op == 1)
print(query(x));
else {
read(v);
a[x] = v;
update(x);
}
}
}
}
int main() {
#ifdef LOCAL
freopen("Test.in", "r", stdin);
#endif
Run();
return 0;
}
J. Sequence
题意:
求:
思路:
考虑最后一项最多有
Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MOD = (ll)1e9 + 7;
int t, n;
ll A, B, C, D, P;
ll Biner(ll x) {
ll l = x, r = n, res = l;
x = P / x;
while (r - l >= 0) {
ll mid = (l + r) >> 1;
ll tmp = P / mid;
if (tmp >= x) {
l = mid + 1;
res = mid;
} else
r = mid - 1;
}
return res;
}
struct node {
ll a[3][3];
node() {
memset(a, 0, sizeof a);
}
node operator*(const node &r) const {
node ans = node();
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k) ans.a[i][j] = (ans.a[i][j] + a[i][k] * r.a[k][j] % MOD) % MOD;
return ans;
}
} base;
node qmod(node base, int n) {
node res = node();
res.a[0][0] = B, res.a[0][1] = A;
res.a[0][2] = 1;
while (n) {
if (n & 1)
res = res * base;
base = base * base;
n >>= 1;
}
return res;
}
ll work() {
if (n == 1)
return A;
if (n == 2)
return B;
int l = 3, r;
while (l <= n) {
r = Biner(l);
base.a[2][0] = P / l;
node res = qmod(base, r - l + 1);
B = res.a[0][0], A = res.a[0][1];
l = r + 1;
}
return B;
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%lld%lld%lld%lld%lld%d", &A, &B, &C, &D, &P, &n);
memset(base.a, 0, sizeof base.a);
base.a[0][0] = D, base.a[1][0] = C, base.a[0][1] = 1;
base.a[2][2] = 1;
printf("%lld\n", work());
}
return 0;
}
K. Swordsman
题意:
有五种攻击属性,怪物有五种防御属性,所有攻击属性要大于其对应的防御属性便能将其击杀,击杀后有经验加成,求最多杀死多少怪物。
思路:
用
Code
#include <bits/stdc++.h>
using namespace std;
namespace FastIO {
#define BUF_SIZE 10000005
bool IOerror = false;
inline char NC() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = true;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
template <typename T>
inline void read(T &x) {
char ch;
while (blank(ch = NC()))
;
if (IOerror) {
x = -1;
return;
}
bool flag = false;
if (ch == '-') {
flag = true;
ch = NC();
}
if (!isdigit(ch))
while (!isdigit(ch = NC()))
;
for (x = ch - '0'; isdigit(ch = NC()); x = x * 10 + ch - '0')
;
if (flag)
x *= -1;
}
#undef BUF_SIZE
} // namespace FastIO
using namespace FastIO;
const int maxn = 1e5 + 10;
struct node {
int id;
int v;
node() {}
node(int id, int v) : id(id), v(v) {}
bool operator<(const node &r) const {
return v > r.v;
}
};
priority_queue<node> q[10];
int n, k;
int ans[maxn];
int arr[maxn][20];
int main() {
int t;
read(t);
while (t--) {
read(n), read(k);
for (int i = 1; i <= k; ++i)
while (!q[i].empty()) q[i].pop();
for (int i = 1; i <= k; ++i) read(ans[i]);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= (k * 2); ++j) {
read(arr[i][j]);
}
q[1].push(node(i, arr[i][1]));
}
int cnt = 0;
while (1) {
bool flag = false;
for (int i = 1; i <= k; ++i) {
while (!q[i].empty()) {
node tmp = q[i].top();
if (tmp.v <= ans[i]) {
if (i == k) {
cnt++;
flag = true;
for (int j = 1; j <= k; ++j) ans[j] += arr[tmp.id][j + k];
} else {
tmp.v = arr[tmp.id][i + 1];
q[i + 1].push(tmp);
}
q[i].pop();
} else
break;
}
}
if (!flag)
break;
}
printf("%d\n", cnt);
for (int i = 1; i <= k; ++i) printf("%d%c", ans[i], " \n"[i == k]);
}
return 0;
}
Last update: March 29, 2022
Created: March 29, 2022
Created: March 29, 2022