zoukankan      html  css  js  c++  java
  • 模板题 Problem I Link Cut Tree

    @(XSY)[LCT]

    Description

    你们这么轻松A了前两题,要是AK了我可就惨了,所以这道题一定要是难(shui)题。那出什么难题呢?有了,这样吧,第一题是数,第二题是树,那我就出个同时含有数和树的题不就好了(废话,什么题没有数)。好,那就好办了。看,这里有一个n个节点且节点带权的树,然后我会要你去执行一些操作,处理一些询问。操作和询问有以下4种: 1、‘1 x y’表示将节点x与节点y用一条边相连接,若节点x与节点y本来已经是连通的话,则输出-1表示操作不合法; 2、‘2 x y’表示将当以节点x为根时,节点y与它的父亲节点相连接的边删除,若节点x与节点y本来已经是不连通的话,则输出-1表示操作不合法; 3、‘3 w x y’表示将节点x到节点y路径上的所有点点权加上w,若节点x与节点y本来已经是不连通的话,则输出-1表示操作不合法; 4、‘4 x y’表示请你输出节点x到节点y路径上的所有点中最大的点权,若节点x与节点y本来已经是不连通的话,则输出-1表示操作不合法。 终于有道比较难的题了,这下你们应该不能在1个小时内做出来了吧。什么,你们还有3个小时……

    Input

    第一行一个整数n表示树的节点个数。 接下来n-1行每行两个整数x、y,表示初始状态节点x与节点y间有一条边。 接下来一行n个整数,第i个数表示节点i的初始点权。 接下来一行一个整数m,表示操作数。 接下来m行,每行以‘1 x y’或‘2 x y’ 或‘3 w x y’ 或‘4 x y’的形式描述操作与询问。

    Output

    对于每个合法询问,输出一行一个整数表示最大点权。 对于每个非法询问或操作,输出一行一个整数-1表示非法。

    Sample Input

    5
    1 2
    2 4
    2 5
    1 3
    1 2 3 4 5
    6
    4 2 3
    2 1 2
    4 2 3
    1 3 5
    3 2 1 4
    4 1 4
    

    Sample Output

    3
    -1
    7
    

    HINT

    对于50%的数据:1<=n,m<=1000。 对于100%的数据:1<=n,m<=3*10^5,0<=初始点权,w<=3000。

    Solution

    终于写了一次真的LCT...以前写的都是假的, 时间复杂度根本就不对...
    这一题是极好的模板题, 既有update操作, 也有pushdown操作. pushdown操作只有在splay之前才需要, 而update操作则要特别注意, 要用到的地方包括: splay中的rotate, access操作和cut操作. 总而言之, 就是只要是修改到了辅助树中一个点的儿子节点, 就要对其本身进行update.

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
     
    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;
        }
    }
     
    struct linkCutTree
    {
        struct node
        {
            node *pre, *suc[2];
            int isRoot, rev;
     
            struct data
            {
                int w, mx, tag;
     
                inline void add(int a)
                {
                    w += a, mx += a, tag += a;
                }
            }infr;
     
            inline node()
            {
                pre = suc[0] = suc[1] = NULL;
                isRoot = 1, rev = 0;
                infr.w = infr.mx = infr.tag = 0;
            }
     
            inline int getRelation()
            {
                if(pre == NULL)
                    return -1;
     
                return this == pre->suc[1];
            }
     
            inline void pushdown()
            {
                if(! isRoot)
                    pre->pushdown();
     
                if(rev)
                    reverse();
     
                if(suc[0] != NULL)
                    suc[0]->infr.add(infr.tag);
                 
                if(suc[1] != NULL)
                    suc[1]->infr.add(infr.tag);
     
                infr.tag = 0;
            }
     
            inline void update()
            {
                infr.mx = infr.w;
     
                if(suc[0] != NULL)
                    infr.mx = std::max(infr.mx, suc[0]->infr.mx);
     
                if(suc[1] != NULL)
                    infr.mx = std::max(infr.mx, suc[1]->infr.mx);
            }
     
            inline void reverse()
            {
                std::swap(suc[0], suc[1]);
                rev ^= 1;
                 
                if(suc[0] != NULL)
                    suc[0]->rev ^= 1;
                 
                if(suc[1] != NULL)
                    suc[1]->rev ^= 1;
            }
        };
     
        node *nd;
     
        inline void init(int n)
        {
            nd = new node[n];
        }
     
        inline void rotate(node *u)
        {
            node *pre = u->pre, *prepre = 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->suc[k ^ 1] = pre;
            u->pre = prepre;
     
            if(pre->isRoot)
                pre->isRoot = 0, u->isRoot = 1;
            else
                prepre->suc[pre->getRelation()] = u;
             
            pre->pre = u;
            pre->update(), u->update();
        }
     
        inline void splay(node *u)
        {
            u->pushdown();
     
            while(! u->isRoot)
            {
                if(! u->pre->isRoot)
                    rotate(u->pre->getRelation() == u->getRelation() ? u->pre : u);
     
                rotate(u);
            }
        }
     
        inline void access(node *u)
        {   
            splay(u);
             
            if(u->suc[1] != NULL)
                u->suc[1]->isRoot = 1, u->suc[1] = NULL, u->update();
             
            while(u->pre != NULL)
            {
                node *pre = u->pre;
                splay(pre);
                 
                if(pre->suc[1] != NULL)
                    pre->suc[1]->isRoot = 1;
                 
                pre->suc[1] = u;
                u->isRoot = 0;
                u->update();
                splay(u);
            }
        }
     
        inline void makeRoot(node *u)
        {
            access(u);
            u->rev ^= 1;
        }
     
        inline node* findRoot(node *u)
        {
        	access(u);
        	
            while(u->suc[0] != NULL)
                u = u->suc[0];
            
            access(u); //find root完一定要access一下啊 
            return u;
        }
     
        inline void cut(node *u, node *v)
        {
            makeRoot(u);
            access(v);
    		access(v); 
            v->suc[0]->isRoot = 1, v->suc[0]->pre = NULL, v->suc[0] = NULL;
            v->update();
        }
     
        inline void link(node *u, node *v)
        {
            makeRoot(u);
            access(v);
     		access(v);
            u->pre = v;
            access(u);
        }
     
        inline void modify(node *u, node *v, int a)
        {
            makeRoot(u);
            access(v);
     		access(v);
            v->infr.add(a);
        }
     
        inline int query(node *u, node *v)
        {
            makeRoot(u);
            access(v);
     		access(v);
            return v->infr.mx;
        }
    }org;
     
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("LCT.in", "r", stdin);
        freopen("LCT.out", "w", stdout);
        #endif
         
        using namespace Zeonfai;
     
        int n = getInt();
        org.init(n + 1);
         
        static int *tmp = new int[n << 1];
         
        for(int i = 2; i < n << 1; i += 2)
            tmp[i - 1] = getInt(), tmp[i] = getInt();
     
        for(int i = 1; i <= n; ++ i)
            org.nd[i].infr.add(getInt());
         
        for(int i = 2; i < n << 1; i += 2)
            org.link(org.nd + tmp[i - 1], org.nd + tmp[i]);
         
        delete[] tmp;
     
        int m = getInt();
     
        for(int i = 0; i < m; ++ i)
        {
            int opt = getInt(), u = getInt(), v = getInt();
     
            if(opt == 1)
            {
            	org.makeRoot(org.nd + u);
            	
    			if(org.findRoot(org.nd + v) == org.nd + u)
            		puts("-1");
            	else
            		org.link(org.nd + u, org.nd + v);
            }
            else if(opt == 2)
            {
            	org.makeRoot(org.nd + u);
            	
            	if(org.findRoot(org.nd + v) != org.nd + u)
            		puts("-1");
            	else
                	org.cut(org.nd + u, org.nd + v);
            }
            else if(opt == 3)
            {
                int tmp = getInt();
     			org.makeRoot(org.nd + v);
     	
     			if(org.findRoot(org.nd + tmp) != org.nd + v)
    			 	puts("-1");
    			else
    				org.modify(org.nd + v, org.nd + tmp, u);	
            }
            else if(opt == 4)
            {
            	org.makeRoot(org.nd + u);
            	
            	if(org.findRoot(org.nd + v) != org.nd + u)
            		puts("-1");
            	else
            		printf("%d
    ", org.query(org.nd + u, org.nd + v));
    		}
        }
    }
    
  • 相关阅读:
    Git和SVN之间的五个基本区别
    如何成为一名程序员:我的道路
    产品经理要懂多少技术?
    Unix哲学相关资源汇总
    Android.mk简介
    Android 中的 Service 全面总结
    获取Map集合中数据的方法
    少编码多思考:代码越多 问题越多
    【自定义Android带图片和文字的ImageButton】
    Android task process thread 进程与线程
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6634928.html
Copyright © 2011-2022 走看看