• 树点涂色


    Description

    Solution

    注意到题目中有一个非常引人注目的描述: 开始时每个点的颜色都不同; 每次涂的颜色也与之前的不同. 考虑用LCT来维护答案, 每条实边表示两个点有同种颜色; 每条虚边表示两个点有不同种颜色, 那么一条边到根路径上的不同颜色数量就等于向上走时经过的虚边数量 + 1, 因而操作2的处理就显而易见了. 注意到我们还有操作3的子树查询, 考虑到整棵树的形态在操作中并不会发生改变, 因此我们用DFS序 + 线段树维护每个点到根路径上的虚边数量, 每次操作1时access一个点并对路径上的点的子树在线段树中修改即可.

    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #define vector std::vector
    #define max std::max
    #define swap std::swap
     
    namespace Zeonfai
    {
        inline int getInt()
        {
            int a = 0, sgn = 1;
            char c;
            while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
            while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
            return a * sgn;
        }
    }
    const int N = (int)1e5, LOG = 17;
    int n, m;
    struct segmentTree
    {
        struct node
        {
            int tg, mx;
        }nd[N << 2];
        inline segmentTree() {memset(nd, 0, sizeof(nd));}
        void modify(int u, int L, int R, int pos, int x)
        {
            nd[u].mx = max(nd[u].mx, x);
            if(L == R) return;
            if(pos <= L + R >> 1) modify(u << 1, L, L + R >> 1, pos, x); else modify(u << 1 | 1, (L + R >> 1) + 1, R, pos, x);
        }
        inline void modify(int pos, int x)
        {
            modify(1, 1, n, pos, x);
        }
        inline void pushDown(int u)
        {
            nd[u << 1].tg += nd[u].tg; nd[u << 1].mx += nd[u].tg;
            nd[u << 1 | 1].tg += nd[u].tg; nd[u << 1 | 1].mx += nd[u].tg;
            nd[u].tg = 0;
        }
        void modify(int u, int curL, int curR, int L, int R, int dlt)
        {
            if(curL >= L && curR <= R)
            {
                nd[u].mx += dlt; nd[u].tg += dlt;
                return;
            }
            pushDown(u);
            int mid = curL + curR >> 1;
            if(L <= mid) modify(u << 1, curL, mid, L, R, dlt);
            if(R > mid) modify(u << 1 | 1, mid + 1, curR, L, R, dlt);
            nd[u].mx = max(nd[u << 1].mx, nd[u << 1 | 1].mx);
        }
        inline void modify(int L, int R, int dlt)
        {
            modify(1, 1, n, L, R, dlt);
        }
        int query(int u, int curL, int curR, int L, int R)
        {
            if(curL >= L && curR <= R) return nd[u].mx;
            pushDown(u);
            int mid = curL + curR >> 1, res = 0;
            if(L <= mid) res = max(res, query(u << 1, curL, mid, L, R));
            if(R > mid) res = max(res, query(u << 1 | 1, mid + 1, curR, L, R));
            return res;
        }
        inline int query(int L, int R)
        {
            return query(1, 1, n, L, R);
        }
    }seg;
    struct tree
    {
        struct node
        {
            vector<node*> edg;
            node *suc[2], *pre, *anc[LOG];
            int isRoot, L, R, dep;
            inline node() {suc[0] = suc[1] = NULL; isRoot = 1; edg.clear();}
            inline int getRelation()
            {
                return pre == NULL ? -1 : this == pre->suc[1];
            }
        }nd[N + 1];
        inline void addEdge(int u, int v) {nd[u].edg.push_back(nd + v); nd[v].edg.push_back(nd + u);}
        int clk;
        void DFS(node *u, node *pre)
        {
            u->dep = pre == NULL ? 1 : pre->dep + 1;
            u->anc[0] = pre;
            for(int i = 1; i < LOG; ++ i) if(u->anc[i - 1] != NULL) u->anc[i] = u->anc[i - 1]->anc[i - 1];
            u->pre = pre; seg.modify(u->L = u->R = ++ clk, u->dep);
            for(auto v : u->edg) if(v != pre) DFS(v, u), u->R = v->R;
        }
        inline void build()
        {
            clk = 0;
            DFS(nd + 1, NULL);
        }
        inline void rotate(node *u)
        {
            node *pre = u->pre, *prepre = u->pre->pre;
            int k = u->getRelation();
            if(u->suc[k ^ 1] != NULL) u->suc[k ^ 1]->pre = pre; pre->suc[k] = u->suc[k ^ 1];
            u->pre = prepre; if(! pre->isRoot) prepre->suc[pre->getRelation()] = u; //注意这里应该写的是isRoot
            pre->pre = u; u->suc[k ^ 1] = pre;
            if(pre->isRoot) pre->isRoot = 0, u->isRoot = 1;
        }
        inline void splay(node *u)
        {
            while(! u->isRoot)
            {
                if(! u->pre->isRoot) rotate(u->getRelation() == u->pre->getRelation() ? u->pre : u);
                rotate(u);
            }
        }
        inline node* getSubtreeRoot(node *u)
        {
            for(; u->suc[0] != NULL; u = u->suc[0]);
            return u;
        }
        inline void modify(int _u)
        {
            node *u = nd + _u;
            splay(u);
            if(u->suc[1] != NULL)
            {
                u->suc[1]->isRoot = 1;
                node *rt = getSubtreeRoot(u->suc[1]); seg.modify(rt->L, rt->R, 1);
                u->suc[1] = NULL;
            }
            while(u->pre != NULL)
            {
                splay(u->pre);
                if(u->pre->suc[1] != NULL)
                {
                    u->pre->suc[1]->isRoot = 1;
                    node *rt = getSubtreeRoot(u->pre->suc[1]); seg.modify(rt->L, rt->R, 1);
                }
                node *rt = getSubtreeRoot(u); seg.modify(rt->L, rt->R, -1);
                u->pre->suc[1] = u; u->isRoot = 0;
                splay(u);
            }
        }
        inline node* getLCA(node *u, node *v)
        {
            if(u->dep < v->dep) swap(u, v);
            for(int i = LOG - 1; ~ i; -- i) if(u->dep - (1 << i) >= v->dep) u = u->anc[i];
            if(u == v) return u;
            for(int i = LOG - 1; ~ i; -- i) if(u->anc[i] != v->anc[i]) u = u->anc[i], v = v->anc[i];
            return u->anc[0];
        }
        inline int query(int u, int v)
        {
            node *LCA = getLCA(nd + u, nd + v);
            return seg.query(nd[u].L, nd[u].L) + seg.query(nd[v].L, nd[v].L) - 2 * seg.query(LCA->L, LCA->L) + 1;
        }
        inline int query(int pos)
        {
            return seg.query(nd[pos].L, nd[pos].R);
        }
    }T;
    int main()
    {
     
        #ifndef ONLINE_JUDGE
     
        freopen("BZOJ4817.in", "r", stdin);
        freopen("BZOJ4817.out", "w", stdout);
     
        #endif
     
        using namespace Zeonfai;
        n = getInt(), m = getInt();
        for(int i = 1; i < n; ++ i)
        {
            int u = getInt(), v = getInt();
            T.addEdge(u, v);
        }
        T.build();
        for(int i = 0; i < m; ++ i)
        {
            int opt = getInt();
            if(opt == 1)
            {
                int u = getInt();
                T.modify(u);
            }
            else if(opt == 2)
            {
                int u = getInt(), v = getInt();
                printf("%d
    ", T.query(u, v));
            }
            else if(opt == 3)
            {
                int u = getInt();
                printf("%d
    ", T.query(u));
            }
        }
    }
    
  • 相关阅读:
    VBA操作IE
    Eclipse中Git图标表示内容
    sqldeveloper更改语言设定
    VBA-FileToFileUpdate
    VBA-UTF-8文件的操作
    Null项目参与排序
    阿里云的学生机如何开放全部端口
    .net core3.1 webapi + vue + element-ui upload组件实现文件上传
    .net core控制台使用log4net
    vue2.x中使用三元表达式绑定class的时候遇到的坑
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7367344.html
Copyright © 2020-2023  润新知