zoukankan      html  css  js  c++  java
  • BZOJ 3589 动态树(子树操作,链查询)

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3589

    题意:给出一棵有根树,两种操作:(1)以u为根的子树所有节点权值加上一个数字;(2)给出若干个链,求这些链的节点的权值和。重复的节点的权值只计算一次。

    思路:AAA树:每个节点有四个孩子,0和1是动态树的左右孩子,其他的孩子弄成一个二叉树保存在2 3号节点上。

    void add(i64 &x,i64 y)
    {
    	x=(x+y)&(mod-1);
    }
    
    struct node
    {
        node *c[4],*p;
    
        i64 chainMark,treeMark;
    	int size;
    	i64 sum;
      
        int inner,rev;
    	i64 val;
      
        node()
        {
            c[0]=c[1]=c[2]=c[3]=p=0;
            inner=1;
            rev=0;
            val=0;
    		sum=0;
    		size=1;
        }
      
        node(int x)
        {
            c[0]=c[1]=c[2]=c[3]=p=0;
            inner=0;
            rev=0;
            val=x;
    		size=1;
            pushUp();
        }
      
        void pushUp()
        {
            if(!inner) sum=val,size=1;
    		else size=1;
            int i;
            for(i=0;i<2;i++) if(c[i])
            {
    			size+=c[i]->size;
    			add(sum,c[i]->sum);
            }
        }
      
        void reverse()
        {
    		swap(c[0],c[1]);
            rev^=1;
        }
      
        void updateChain(i64 a)
        {
    		add(chainMark,a);
    		add(sum,size*a);
    		add(val,a);
        }
      
        void updateTree(i64 a,int flag=1)
        {
    		add(treeMark,a);
            if(flag) updateChain(a);
        }
      
        void pushDown()
        {
            if(rev)
            {
                if(c[0]) c[0]->reverse();
                if(c[1]) c[1]->reverse();
                rev=0;
            }
            if(treeMark)
            {
                int i;
                for(i=0;i<4;i++) if(c[i]) c[i]->updateTree(treeMark,i>=2);
                treeMark=0;
            }
            if(chainMark)
            {
                if(c[0]) c[0]->updateChain(chainMark);
                if(c[1]) c[1]->updateChain(chainMark);
                chainMark=0;
            }
        }
      
        int isRoot(int t)
        {
            if(t==0) return !p||(p->c[0]!=this&&p->c[1]!=this);
            return !p||!p->inner||!inner;
        }
      
        void setSon(node *son,int id)
        {
            c[id]=son;
            if(son) son->p=this;
        }
      
        int pos()
        {
            int i;
            for(i=0;i<4;i++) if(p->c[i]==this) return i;
            return -1;
        }
      
        node* getSon(int id)
        {
            if(c[id]) c[id]->pushDown();
            return c[id];
        }
      
        int dir(int t)
        {
            return p->c[t+1]==this;
        }
    };
      
      
    /**
     *t=0 d=0: 右旋
     *t=0 d=1: 左旋
     *
     * **/
    void rot(node *u,int t)
    {
        node *p=u->p;
        int d=u->dir(t);
        if(p->p) p->p->setSon(u,p->pos());
        else u->p=0;
        p->setSon(u->c[!d+t],d+t);
        u->setSon(p,!d+t);
        p->pushUp();
    }
      
    /**
     *t=0 or 2
     * **/
    void splay(node *u,int t=0)
    {
        while(!u->isRoot(t))
        {
            if(u->p->isRoot(t)) rot(u,t);
            else if(u->p->dir(t)==u->dir(t)) rot(u->p,t),rot(u,t);
            else rot(u,t),rot(u,t);
        }
        u->pushUp();
    }
      
      
    /**
     *把节点u的父亲设为v
     * **/
    void add(node *u,node *v)
    {
        v->pushDown();
        int i;
        for(i=2;i<4;i++) if(!v->c[i])
        {
            v->setSon(u,i);
            return;
        }
      
        node *tmp=v,*x=new node;
        while(tmp->c[2]->inner) tmp=tmp->getSon(2);
        x->setSon(tmp->c[2],2);
        x->setSon(u,3);
        tmp->setSon(x,2);
        splay(x,2);
    }
      
      
    /**
     *将节点u从其父节点断开
     * **/
    void del(node *u)
    {
        if(u->p->inner)
        {
    		node *q=u->p->c[5-u->pos()];
            u->p->p->setSon(q,u->p->pos());
            node *tmp=u->p;
    		splay(u->p->p,2);
            delete tmp;
        }
        else
        {
            u->p->setSon(0,u->pos());
        }
        u->p=0;
    }
      
      
    node *st[N];
    int top;
      
      
      
    void pushDown(node *u)
    {
        top=0;
        while(u) st[++top]=u,u=u->p;
        while(top>0) st[top]->pushDown(),top--;
      
    }
      
      
    void access(node *u)
    {
        node *v=u,*tmp;
        pushDown(u);
        splay(u);
        if(u->c[1]) tmp=u->c[1],u->c[1]=0,add(tmp,u),u->pushUp();
      
        while(u->p)
        {
            for(tmp=u->p;tmp->inner;tmp=tmp->p);
            splay(tmp);
            if(tmp->c[1])
            {
                u->p->setSon(tmp->c[1],u->pos());
                splay(u->p,2);
                tmp->setSon(u,1);
            }
            else
            {
                del(u);
                tmp->setSon(u,1);
            }
      
            u=tmp;
            u->pushUp();
        }
        splay(v);
    }
      
      
    void makeRoot(node *u)
    {
        access(u);
        u->reverse();
    }
       
    int n,m;
    node *a[N];
      
     
    vector<int> g[N];
    int f[N][20];
    int dep[N];
     
    void DFS(int u,int pre,int d)
    {
        f[u][0]=pre;
        dep[u]=d;
             
        int i;
        for(i=0;i<SZ(g[u]);i++)
        {
            int v=g[u][i];
            if(v==pre) continue;
            add(a[v],a[u]);
            DFS(v,u,d+1);
        }
        a[u]->pushUp();
    }
     
    void init()
    {
        DFS(1,0,1);
        int i,j;
        for(i=1;i<20;i++) for(j=1;j<=n;j++)
        {
            f[j][i]=f[f[j][i-1]][i-1];
        }
    }
     
     
    int jump(int u,int x)
    {
        int i;
        for(i=0;i<20;i++) if(x&(1<<i)) u=f[u][i];
        return u;
    }
     
    int getLca(int u,int v)
    {
        if(u==0||v==0) return 0;
     
        if(u==v) return u;
        if(dep[u]<dep[v]) swap(u,v);
        int det=dep[u]-dep[v];
        u=jump(u,det);
        if(v==u) return u;
        int i;
        for(i=19;i>=0;i--) if(f[u][i]&&f[v][i]&&f[u][i]!=f[v][i])
        {
            u=f[u][i];
            v=f[v][i];
        }
        return f[u][0];
    }
     
     
    struct Query
    {
        int u,v;
     
        void get()
        {
            u=getInt();
            v=getInt();
            if(dep[u]<dep[v]) swap(u,v);
            v=f[v][0];
        }
     
        int operator<(const Query &a) const
        {
            return dep[v]<dep[a.v];
        }
    };
     
     
    i64 cal(int u,int v)
    {
        if(u==v) return 0;
        v=jump(u,dep[u]-dep[v]-1);
     
        makeRoot(a[u]);
        access(a[v]);
        splay(a[u]);
        i64 ans=a[u]->sum;
     
        return ans;
    }
     
     
    int main()
    {
      
        n=getInt();
        int i;
        for(i=0;i<n-1;i++)
        {
            int u=getInt();
            int v=getInt();
            g[u].pb(v);
            g[v].pb(u);
        }
     
        for(i=1;i<=n;i++)  a[i]=new node(0);
        init();
      
        makeRoot(a[1]);
      
        m=getInt();
     
        while(m--)
        {
            int op=getInt();
            if(op==0)
            {
                int u=getInt();
                i64 det=getInt();
     
                node *p=a[u];
                access(p);
                p->val+=det;
                for(i=2;i<4;i++) if(p->c[i]) p->c[i]->updateTree(det);
                p->pushUp();
            }
            else
            {
                int K=getInt();
                Query q[10];
                for(i=1;i<=K;i++) q[i].get();
                sort(q+1,q+K+1);
     
                i64 ans=0;
                for(i=1;i<=K;i++)
                {
                    int j;
                    for(j=1;j<i;j++)
                    {
                        int lca=getLca(q[i].u,q[j].u);
                        if(dep[lca]>dep[q[i].v]) q[i].v=lca;
                    }
                    ans+=cal(q[i].u,q[i].v);
                }
     
                ans%=mod;
                if(ans<0) ans+=mod;
     
                output(ans); puts("");
                makeRoot(a[1]);
            }
        }
    }
    
  • 相关阅读:
    LInux-crontab
    Linux权限-chmod1
    Tool_BurpSuite安装和简单使用
    python与redis交互(四)
    Flask_环境部署(十六)
    Nginx_配置文件nginx.conf配置详解
    Tool_linux环境安装python3和pip
    Nginx_全局命令设置
    Linux_无法解析域名
    VMware_克隆机器后主机Ping不同虚拟机,虚拟机能Ping通主机
  • 原文地址:https://www.cnblogs.com/jianglangcaijin/p/4002036.html
Copyright © 2011-2022 走看看