zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    windows下面编译redis5.0.5
    在ASP.NET Core 2.x中获取客户端IP地址
    https网站访问第三方https网站时候报错: The request was aborted:Could not create SSL/TLS secure channel.
    大量日志Login failed for user 'sa'. 原因: 密码与所提供的登录名不匹配。 [客户端: x.x.x.x] 导致Sql Server 的ErrorLog文件过大几十G
    一次清除SQL SERVER错误日志(ErrorLog)的体会!
    notepad++正则抽取所有符合条件的字符串
    Android编译执行envsetup.sh,产生工具命令m、mm、mmm、mmma、tapas 、croot、cgrep、jgrep、 resgrep、godir
    全志Tina_dolphin播放音视频裸流(h264,pcm)验证
    全志Linux Tina编译demoOmxVdec错误
    linux epoll学习
  • 原文地址:https://www.cnblogs.com/Dr-Albert-Wensley/p/log.html
Copyright © 2011-2022 走看看