20210805K 复盘
犯了一些傻逼错误,挂了很多分,气愤
A.s2oj565 Sign
随便树形 dp 即可
ps. 根据研究,极限数据下答案是可能爆 long long 的,但是出题人没有卡
B.s2oj566 Map
随便推式子计算即可,设 \(f[i]\) 表示时间在 \(i\) 时在 \(1\) 号点的概率,容易发现:
\[\large f[i] = (1-f[i-1])\times\frac{1}{n-1}
\]
逐项展开,等比数列求和,得到通项
\[\large \text{ans} = \frac{1-\left((-1)\cdot\dfrac{1}{n-1}\right)^{m-1}}{n}
\]
算就行了。一定要注意的是:
在读入的时候要看看 n 是不是该模
有可能一开始读进来的 n 大于模数,快速幂一乘会爆 long long,100pts -> 60pts
C.s2oj567 Path
很板子的线段树优化建图题。
要注意的是:线段树优化建图的时候区间区间连区间的话,是要新建节点的
不新建中转节点直接两两连边边数是 \({\cal O}(m\log ^2n)\) 的,无论如何都会边数爆炸,100pts -> 85pts
手写两个栈拼的双端队列可以某种程度上优化 01 最短路的速度
#include <bits/stdc++.h>
using namespace std;
const int N = 500010;
int NEWID_cnt, n, m, s;
int head[N * 9], ver[20000003], nxt[20000003], tot;
char edge[20000003];
__attribute__((always_inline))
inline void add(int u, int v, char w) {
ver[++tot] = v; nxt[tot] = head[u]; head[u] = tot; edge[tot] = w;
}
inline int read(register int x = 0, unsigned char ch = getchar()) {
for ( ; !isdigit(ch); ch = getchar());
for ( ; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x;
}
#define mid ((tree[x].l + tree[x].r) >> 1)
#define ls (x << 1)
#define rs ((x << 1) + 1)
namespace tree{
struct NODE{
int l, r, newid, newid2;
}tree[N << 2];
void build(int l, int r, int x) {
tree[x].l = l, tree[x].r = r;
tree[x].newid = ++NEWID_cnt;
tree[x].newid2 = ++NEWID_cnt;
if (l == r) {
add(l, tree[x].newid, 0);
add(tree[x].newid2, l, 0);
return;
}
build(l, mid, ls);
build(mid + 1, r, rs);
add(tree[ls].newid, tree[x].newid, 0);
add(tree[x].newid2, tree[ls].newid2, 0);
add(tree[rs].newid, tree[x].newid, 0);
add(tree[x].newid2, tree[rs].newid2, 0);
}
void link(int l, int r, int p, int x) {
if (tree[x].l == l && tree[x].r == r) {
add(tree[x].newid, p, 1);
return;
}
if (r <= mid) link(l, r, p, ls);
else if (l > mid) link(l, r, p, rs);
else link(l, mid, p, ls), link(mid + 1, r, p, rs);
}
void collect(int l, int r, int p, int x) {
if (tree[x].l == l && tree[x].r == r) {
add(p, tree[x].newid2, 0);
return;
}
if (r <= mid) collect(l, r, p, ls);
else if (l > mid) collect(l, r, p, rs);
else collect(l, mid, p, ls), collect(mid + 1, r, p, rs);
}
}
#undef mid
#undef ls
#undef rs
int dis[N * 9]; bool vis[N * 9];
int sta1[5000003], sta2[5000003];
void dij() {
memset(dis, 0x3f, sizeof(int) * (NEWID_cnt + 10));
register int L1, R1, L2, R2;
dis[s] = 0;
L1 = 1, R1 = 1, L2 = 1, R2 = 0;
sta1[R1] = s;
register int x;
while ((L1 <= R1) || (L2 <= R2)) {
if (L1 <= R1) x = sta1[R1--];
else x = sta2[L2++];
if (vis[x]) continue;
vis[x] = true;
for (register int i = head[x], y; i && (y = ver[i], true); i = nxt[i]) {
if (dis[y] > dis[x] + edge[i]) {
dis[y] = dis[x] + edge[i];
if (!edge[i]) {
if (L2 == 1) sta1[++R1] = y;
else sta2[--L2] = y;
} else {
sta2[++R2] = y;
}
}
}
}
}
int main() {
n = read(), m = read(), s = read();
NEWID_cnt = n;
tree::build(1, n, 1);
for (register int i = 1, l1, r1, l2, r2; i <= m; i++) {
l1 = read(), r1 = read(), l2 = read(), r2 = read();
int now = ++NEWID_cnt;
tree::collect(l2, r2, now, 1);
tree::link(l1, r1, now, 1);
now = ++NEWID_cnt;
tree::collect(l1, r1, now, 1);
tree::link(l2, r2, now, 1);
}
dij();
for (int i = 1; i <= n; i++)
printf("%d\n", dis[i]);
}
/*
5 3 4
1 2 4 5
1 1 3 3
4 4 5 5
*/
D.s2oj568 星际探索
很 ett 的题,不用写完整版本的 ett,但是基本借用 ett 思想
将原树按照欧拉序展开,换子树就是将一段区间平移。
将欧拉序中一个点出现的第一次赋成正点权,最后一次赋成负点权,查询到根的路径就是查询前缀和
子树加打标记即可。splay 中要维护 siz 表示 "子树内的 fir 个数 - las 个数"
注意:splay 接子树的时候要将 ch <-> fa 的双向关系都接上
考场上没想太清楚,写码未遂
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 200010;
int head[N], ver[N], nxt[N], tot;
int DFN_cnt, dfn[N], fir[N], las[N];
inline void add(int u, int v) {
ver[++tot] = v; nxt[tot] = head[u]; head[u] = tot;
}
int w[N];
__attribute__((always_inline))
inline int read(register int x = 0, unsigned char ch = getchar()) {
for ( ; !isdigit(ch); ch = getchar());
for ( ; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x;
}
namespace splay{
int root;
int ch[N][2], siz[N], fa[N];
ll sum[N], tag[N], id[N], val[N];
void update(int p) {
siz[p] = siz[ch[p][0]] + siz[ch[p][1]] + id[p];
sum[p] = sum[ch[p][0]] + sum[ch[p][1]] + val[p];
}
void addon(int p, ll v) {
tag[p] += v;
sum[p] += siz[p] * v;
val[p] += v * id[p];
}
int ident(int p) { return p == ch[fa[p]][1]; }
void rotate(int p) {
int x = fa[p]; int y = fa[x];
int idx = ident(x), idp = ident(p);
ch[y][idx] = p; fa[p] = y;
ch[x][idp] = ch[p][idp ^ 1]; fa[ch[p][idp ^ 1]] = x;
ch[p][idp ^ 1] = x; fa[x] = p;
update(x);
}
void pushdown(int p) {
addon(ch[p][0], tag[p]);
addon(ch[p][1], tag[p]);
tag[p] = 0;
}
void pushall(int p) {
if (fa[p]) pushall(fa[p]);
if (tag[p]) pushdown(p);
}
void splay(int p, int target = 0) {
pushall(p);
while (fa[p] != target) {
if (fa[fa[p]] == target) rotate(p);
else if (ident(fa[p]) == ident(p)) rotate(fa[p]), rotate(p);
else rotate(p), rotate(p);
}
update(p);
if (!target) root = p;
}
int build(int l, int r) {
int now = (l + r) >> 1;
if (l < now) ch[now][0] = build(l, now - 1), fa[ch[now][0]] = now;
if (now < r) ch[now][1] = build(now + 1, r), fa[ch[now][1]] = now;
update(now);
return now;
}
int getPre(int p) {
splay(p);
int ret = ch[p][0];
while (ch[ret][1]) ret = ch[ret][1];
return splay(ret), ret;
}
int getNxt(int p) {
splay(p);
int ret = ch[p][1];
while (ch[ret][0]) ret = ch[ret][0];
return splay(ret), ret;
}
}
void dfs(int x, int fax) {
dfn[++DFN_cnt] = x;
fir[x] = DFN_cnt;
splay::val[DFN_cnt] = w[x];
splay::id[DFN_cnt] = 1;
for (int i = head[x], y; i && (y = ver[i], true); i = nxt[i])
if (y != fax) dfs(y, x);
dfn[++DFN_cnt] = x;
las[x] = DFN_cnt;
splay::val[DFN_cnt] = -w[x];
splay::id[DFN_cnt] = -1;
}
int n, m;
int main() {
// cout << "tag" << endl;
n = read();
for (int i = 2; i <= n; i++) add(read(), i);
for (int i = 1; i <= n; i++) w[i] = read();
DFN_cnt = 1;
dfs(1, 0);
DFN_cnt++; // 保留哨兵节点
splay::root = splay::build(1, DFN_cnt);
m = read();
char op[5];
for (int i = 1, x, y, v; i <= m; i++) {
scanf("%s", op);
if (op[0] == 'Q') {
x = fir[read()];
splay::splay(x);
printf("%lld\n", splay::sum[splay::ch[x][0]] + splay::val[x]);
} else if (op[0] == 'C') {
x = read(), y = read();
int pre = splay::getPre(fir[x]);
int nxt = splay::getNxt(las[x]);
splay::splay(pre); splay::splay(nxt, pre);
int del = splay::ch[nxt][0];
splay::ch[nxt][0] = 0; splay::update(nxt); splay::update(pre);
pre = fir[y];
nxt = splay::getNxt(pre);
splay::splay(pre); splay::splay(nxt, pre);
splay::ch[nxt][0] = del; splay::fa[del] = nxt;
splay::update(nxt); splay::update(pre);
splay::splay(del);
} else {
x = read(), v = read();
int pre = splay::getPre(fir[x]);
int nxt = splay::getNxt(las[x]);
splay::splay(pre); splay::splay(nxt, pre);
int del = splay::ch[nxt][0];
splay::addon(del, v);
splay::update(nxt); splay::update(pre);
splay::splay(del);
}
}
}

浙公网安备 33010602011771号