Log

2021-08-05

贪心训练。

活动安排&种树:贪心板子题

思维上没有太大难度。

#include<bits/stdc++.h>
using namespace std;
 
struct NODE
{
    int start,end;
};
NODE action[1001];
inline bool COMPARE(NODE,NODE);
 
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>action[i].start>>action[i].end;
    sort(action+1,action+n+1,COMPARE);
    int time=action[1].end,answer=1;
    for(int i=2;i<=n;i++)
        if(action[i].start>=time)
        {
            answer++;
            time=action[i].end;
        }
    cout<<answer<<endl;
    return 0;
}

bool COMPARE(NODE x,NODE y)
{
    return x.end<y.end;
}
#include <bits/stdc++.h>
#define maxn 100500
#define man 5500
using namespace std;

struct NODE
{
    int l, r, val;
};
NODE e[man];
int n, m, mp[maxn];
inline bool CMP(NODE, NODE);

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; ++i)
        scanf("%d%d%d", &e[i].l, &e[i].r, &e[i].val);
    sort(e, e + m, CMP);
    for (int i = 0; i < m; ++i)
    {
        int sum = 0;
        for (int j = e[i].l; j <= e[i].r; ++j)
            sum += mp[j];
        for (int j = e[i].r; sum < e[i].val; --j)
            if (!mp[j])
            {
                mp[j] = 1;
                sum++;
            }
    }
    int ans = 0;
    for (int i = 1; i <= n; ++i)
        ans += mp[i];
    printf("%d
", ans);
    return 0;
}

inline bool CMP(NODE a, NODE b)
{
    return a.r < b.r;
}

2021-08-03

树上莫队、回滚莫队。

树上莫队理解

把树的括号序分块跑莫队,把树压成一维的。

Luogu P4074 糖果公园

给一棵每个点带有颜色的树,每次询问 (sum _c val_c sum ^{cnt_c} _{i = 1} w_i)

val:该颜色的价值;

cnt:颜色出现的次数;

w:该颜色出现 i 次后的价值。

先把树变成序列,然后每次添加/删除一个点,这个点的对答案贡献 (val_c imes w_{cnt_{c + 1}})

扫的过程中起点的子树里的点肯定会被扫两次,但贡献为0。

开一个vis数组,每次扫到点x,就把 (vis_x) 异或上 (1)

(vis_x = 0) 时点贡献不计。

最后套上昨天的带修莫队。

#include <bits/stdc++.h>
#define maxn 200010
using namespace std;

int f[maxn], g[maxn], id[maxn], head[maxn], cnt, last[maxn], dep[maxn], fa[maxn][22], v[maxn], w[maxn],pos[maxn], col[maxn], app[maxn];
int block, index, n, m, q;
bool vis[maxn];
long long int ans[maxn], cur;

struct EDGE
{
    int to, nxt;
};
EDGE e[maxn];
int cnt1 = 0, cnt2 = 0;

struct QUERY
{
    int l, r, t, id;
    bool operator<(const QUERY &b) const
    {
        return (pos[l] < pos[b.l]) || (pos[l] == pos[b.l] && pos[r] < pos[b.r]) || (pos[l] == pos[b.l] && pos[r] == pos[b.r] && t < b.t);
    }
};
QUERY a[maxn], b[maxn];

inline void addEDGE(int x, int y)
{
    e[++cnt] = (EDGE){
        y, head[x]};
    head[x] = cnt;
}

void dfs(int x)
{
    id[f[x] = ++index] = x;
    for (int i = head[x]; i; i = e[i].nxt)
    {
        if (e[i].to != fa[x][0])
        {
            fa[e[i].to][0] = x;
            dep[e[i].to] = dep[x] + 1;
            dfs(e[i].to);
        }
    }
    id[g[x] = ++index] = x; 
}

inline void swap(int &x, int &y)
{
    int t;
    t = x;
    x = y;
    y = t;
}

inline int lca(int x, int y)
{
    if (dep[x] < dep[y])
        swap(x, y);
    if (dep[x] != dep[y])
    {
        int dis = dep[x] - dep[y];
        for (int i = 20; i >= 0; i--)
            if (dis >= (1 << i))
                dis -= 1 << i, x = fa[x][i];
    } 
    if (x == y)
        return x;
    for (int i = 20; i >= 0; i--)
    {
        if (fa[x][i] != fa[y][i])
            x = fa[x][i], y = fa[y][i];
    }
    return fa[x][0];
}

inline void add(int x)
{
    if (vis[x])
        cur -= (long long)v[col[x]] * w[app[col[x]]--];
    else
        cur += (long long)v[col[x]] * w[++app[col[x]]];
    vis[x] ^= 1;
}

inline void modify(int x, int t)
{
    if (vis[x])
    {
        add(x);
        col[x] = t;
        add(x);
    }
    else
        col[x] = t;
} 

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= m; i++)
        scanf("%d", &v[i]);
    for (int i = 1; i <= n; i++)
        scanf("%d", &w[i]);
    for (int i = 1; i < n; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        addEDGE(x, y);
        addEDGE(y, x);
    }
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &last[i]);
        col[i] = last[i];
    }
    dfs(1);
    for (int j = 1; j <= 20; j++)
        for (int i = 1; i <= n; i++)
            fa[i][j] = fa[fa[i][j - 1]][j - 1]; 
    int block = pow(index, 2.0 / 3);
    for (int i = 1; i <= index; i++)
    {
        pos[i] = (i - 1) / block;
    }
    while (q--)
    {
        int opt, x, y;
        scanf("%d%d%d", &opt, &x, &y);
        if (opt == 0)
        {
            b[++cnt2].l = x;
            b[cnt2].r = last[x];
            last[x] = b[cnt2].t = y;
        }
        else
        {
            if (f[x] > f[y])
                swap(x, y);
            a[++cnt1] = (QUERY){
                lca(x, y) == x ? f[x] : g[x], f[y], cnt2, cnt1};
        }
    }
    sort(a + 1, a + cnt1 + 1);
    int L, R, T; 
    L = R = 0;
    T = 1;
    for (int i = 1; i <= cnt1; i++)
    {
        while (T <= a[i].t)
        {
            modify(b[T].l, b[T].t);
            T++;
        }
        while (T > a[i].t)
        {
            modify(b[T].l, b[T].r);
            T--;
        }
        while (L > a[i].l)
        {
            L--;
            add(id[L]);
        }
        while (L < a[i].l)
        {
            add(id[L]);
            L++;
        }
        while (R > a[i].r)
        {
            add(id[R]);
            R--;
        }
        while (R < a[i].r)
        {
            R++;
            add(id[R]);
        }
        int x = id[L], y = id[R];
        int llca = lca(x, y);
        if (x != llca && y != llca)
        {
            add(llca);
            ans[a[i].id] = cur;
            add(llca);
        }
        else
            ans[a[i].id] = cur;
    }
    for (int i = 1; i <= cnt1; i++)
    {
        printf("%lld
", ans[i]);
    }
    return 0;
}

2021-08-02

主要学习带修莫队。

对带修莫队的大概理解:

在普通莫队上用于 DP 类似的思想强行加上一维表示操作时间,询问时也相应加上一维,由 ([l , r]) 变为 ([l , r , time]),坐标移动时也加一维变成

  • ([l - 1 , r , time])

  • ([l + 1 , r , time])

  • ([l , r - 1 , time])

  • ([l , r + 1 , time])

  • ([l , r , time - 1])

  • ([l , r , time + 1])

转移仍保持 (O(1))

裸题 BZOJ 2120

#include <bits/stdc++.h>
#define N 200007
using namespace std;

struct ques
{
    int l, r, num, tim;
} q[N];
int nn[N << 3], n, m, a[N], ans[N], bl[N];

inline bool CMP(ques, ques);

int cp[N], cx[N];
int main()
{
    cin >> n >> m;
    int cntq = 0, cntr = 0;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    int size = pow(n, 2.0 / 3.0), bn = ceil((double)n / size);
    char c[26];
    for (int i = 1; i <= bn; i++)
        for (int j = (i - 1) * size + 1; j <= i * size, j <= n; j++)
            bl[j] = i;
    for (int i = 1; i <= m; i++)
    {
        int x, y;
        scanf("%s", c);
        scanf("%d%d", &x, &y);
        if (c[0] == 'Q')
            q[++cntq].l = x, q[cntq].r = y, q[cntq].num = cntq, q[cntq].tim = cntr;
        if (c[0] == 'R')
        {
            cp[++cntr] = x;
            cx[cntr] = y;
        }
    }
    sort(q + 1, q + 1 + cntq, CMP);
    int l = 1, r = 0, time = 0, cnt = 0;
    for (int i = 1; i <= cntq; i++)
    {
        int ql = q[i].l, qr = q[i].r, qt = q[i].tim;
        while (l < ql)
        {
            nn[a[l]]--;
            if (nn[a[l]] == 0)
                cnt--;
            l++;
        }
        while (l > ql)
        {
            l--;
            nn[a[l]]++;
            if (nn[a[l]] == 1)
                cnt++;
        }
        while (r < qr)
        {
            r++;
            nn[a[r]]++;
            if (nn[a[r]] == 1)
                cnt++;
        }
        while (r > qr)
        {
            nn[a[r]]--;
            if (nn[a[r]] == 0)
                cnt--;
            r--;
        }
        while (time < qt)
        {
            time++;
            int x = cp[time];
            if (ql <= x && x <= qr)
            {
                nn[a[x]]--;
                if (nn[a[x]] == 0)
                    cnt--;
            }
            swap(a[x], cx[time]);
            if (ql <= x && x <= qr)
            {
                if (nn[a[x]] == 0)
                    cnt++;
                nn[a[x]]++;
            }
        }
        while (time > qt)
        {
            int x = cp[time];
            if (ql <= x && x <= qr)
            {
                nn[a[x]]--;
                if (nn[a[x]] == 0)
                    cnt--;
            }
            swap(a[x], cx[time]);
            if (ql <= x && x <= qr)
            {
                if (nn[a[x]] == 0)
                    cnt++;
                nn[a[x]]++;
            }
            time--;
        }
        ans[q[i].num] = cnt;
    }
    for (int i = 1; i <= cntq; i++)
        printf("%d
", ans[i]);
}

inline bool CMP(ques a, ques b)
{
    if (bl[a.l] != bl[b.l])
        return bl[a.l] < bl[b.l];
    else
    {
        if (bl[a.r] == bl[b.r])
            return a.tim < b.tim;
        else
        {
            if (bl[a.l] & 1)
                return bl[a.r] < bl[b.r];
            else
                return bl[a.r] > bl[b.r];
        }
    }
}

另尝试解决 CodeForces 1396E(DP题),但只推导出 (minans = sum ^ n _{i =1} [i ot = root] sz[i] pmod 2)
(maxans = sum ^n _{i = 1} [i ot = root] sz[i])

没有思考出如何判断有解,爆零。

看了看题解,推不动如何证明答案有解的充分条件,就放弃了。

whk进度条 40/283

2021-07-31

  • [CSP-S2019] 树的重心

题意可得树深度较浅,因此暴力换重儿子。

根据重心定义,对于一个点 (x),若 (x) 不是重心,则中心要么在重儿子子树内,要么在父亲节点上。

第一次深搜求出儿子树与子树结点数。

第二次深搜换根,对于一条边,以下方的重心可以直接跳倍增,可以跳的条件为上方 (size le dfrac{sum}{2})

对于上方的重心,换根时记录信息,倍增方法相同。

#include <bits/stdc++.h>
#define N 300005
using namespace std;

struct NODE
{
    int to, next;
};
int n, T, son[N], s[N], pr[N], son2[N], p[N][18], son3[N], f[N], h[N], cnt, s2[N];
long long int ans;
NODE w[N << 1];
inline int READ();
inline void ADD(int, int);
void DFS(int, int);
inline int JUDGE(int, int);
void DFS2(int, int);

int main()
{
    freopen("centroid.in", "r", stdin);
    freopen("centroid.out", "w", stdout);
    T = READ();
    while (T--)
    {
        memset(h, 0, sizeof(h));
        memset(son, 0, sizeof(son));
        memset(f, 0, sizeof(f));
        memset(pr, 0, sizeof(pr));
        cnt = 0, ans = 0, n = READ();
        for (int i = 1; i < n; i++)
        {
            int x = READ(), y = READ();
            ADD(x, y);
            ADD(y, x);
        }
        DFS(1, 0);
        memcpy(s2, s, sizeof(s2));
        memcpy(son3, son, sizeof(son3));
        memcpy(f, pr, sizeof(f));
        DFS2(1, 0);
        printf("%lld
", ans);
    }
    return 0;
}

inline int READ()
{
    int data = 0, w = 1;
    char ch = 0;
    while (ch != '-' && (ch < '0' || ch > '9'))
        ch = getchar();
    if (ch == '-')
        w = -1, ch = getchar();
    while (ch >= '0' && ch <= '9')
        data = (data << 1) + (data << 3) + (ch ^ 48), ch = getchar();
    return data * w;
}

inline void ADD(int x, int y)
{
    ++cnt;
    w[cnt].to = y;
    w[cnt].next = h[x];
    h[x] = cnt;
    return;
}

void DFS(int x, int fa)
{
    s[x] = 1;
    pr[x] = fa;
    for (int i = h[x]; i; i = w[i].next)
    {
        int y = w[i].to;
        if (y == fa)
            continue;
        DFS(y, x);
        s[x] += s[y];
        if (s[y] > s[son[x]])
            son2[x] = son[x], son[x] = y;
        else if (s[y] > s[son2[x]])
            son2[x] = y;
    }
    p[x][0] = son[x];
    for (int i = 1; i <= 17; i++)
        p[x][i] = p[p[x][i - 1]][i - 1];
    return;
}

inline int JUDGE(int x, int sum)
{
    return x * (max(s2[son3[x]], sum - s2[x]) <= sum / 2);
}

void DFS2(int x, int fa)
{
    for (int i = h[x]; i; i = w[i].next)
    {
        int y = w[i].to;
        if (y == fa)
            continue;
        s2[x] = s[1] - s[y];
        f[y] = 0;
        f[x] = 0;
        if (son[x] == y)
            son3[x] = son2[x];
        else
            son3[x] = son[x];
        if (s2[fa] > s2[son3[x]])
            son3[x] = fa;
        p[x][0] = son3[x];
        for (int j = 1; j <= 17; j++)
            p[x][j] = p[p[x][j - 1]][j - 1];
        int b = x;
        for (int j = 17; j >= 0; j--)
            if (s2[x] - s2[p[b][j]] <= s2[x] / 2)
                b = p[b][j];
        ans += JUDGE(son3[b], s2[x]) + JUDGE(b, s2[x]) + JUDGE(f[b], s2[x]);
        b = y;
        for (int j = 17; j >= 0; j--)
            if (s2[y] - s2[p[b][j]] <= s2[y] / 2)
                b = p[b][j];
        ans += JUDGE(son3[b], s2[y]) + JUDGE(b, s2[y]) + JUDGE(f[b], s2[y]);
        f[x] = y;
        DFS2(y, x);
    }
    son3[x] = p[x][0] = son[x];
    f[x] = pr[x];
    for (int j = 1; j <= 17; j++)
        p[x][j] = p[p[x][j - 1]][j - 1];
    s2[x] = s[x];
    return;
}

做题情况

  • Luogu P3943 100pts

  • Luogu P5666 100pts

  • JZYZOJ P3745 20pts

原文地址:https://www.cnblogs.com/Dr-Albert-Wensley/p/log.html