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 long100pts -> 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);
        }
    }
}
posted @ 2021-08-05 17:28  熹圜  阅读(9)  评论(0)    收藏  举报