zoukankan      html  css  js  c++  java
  • QTREE5

    QTREE5 - Query on a tree V 

    动态点分治和动态边分治用Qtree4的做法即可。

    LCT:

    换根后,求子树最浅的白点深度。

    但是也可以不换根。类似平常换根的往上g,往下f的拼凑

    考虑深度的pushup必须考虑原树结构的联系,而ch[0],ch[1]又不是直接的前驱后继,每次pushup还要找前驱后继答案,还不如直接记下来。

    故,节点里维护:

    1.sz,大小

    2.color节点颜色

    3.set每个虚儿子贡献的最浅深度

    4.lmn,rmn,当前x的splay子树最浅点和最深点的,展开成的实链的范围内的答案。

    也就是:

    pushup:

    后面的就是跨过x的拼凑。top是虚儿子set的最小值

    access:

    虚实儿子转化

    修改,access,splay,t[x].co^1

    查询:access,splay, cout<<t[x].rmn

    代码:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=100000+5;
    const int inf=0x3f3f3f3f;
    int n,q;
    struct node{
        int ch[2],fa;
        int lmn,rmn;
        int co;//1:white 0:black
        int sz;
        multiset<int>s;
        multiset<int>::iterator it;
        int top(){
            if(s.size()) return *s.begin();
            return inf;
        }
        void ins(int c){
            s.insert(c);
        }
        void dele(int c){
            it=s.lower_bound(c);
            if(it!=s.end()) s.erase(it);
        }
        void op(){
            cout<<" ch[0] "<<ch[0]<<" ch[1] "<<ch[1]<<" fa "<<fa<<endl;
            cout<<" co "<<co<<" sz "<<sz<<endl;
            cout<<" lmn "<<lmn<<"  rmn "<<rmn<<endl;
            cout<<" s.size() "<<s.size()<<endl;
        }
    }t[N];
    int nrt(int x){
        return t[t[x].fa].ch[0]==x||t[t[x].fa].ch[1]==x;
    }
    void pushup(int x){
        if(!x) return;
        t[x].sz=t[t[x].ch[0]].sz+t[t[x].ch[1]].sz+1;
        t[x].lmn=min(t[t[x].ch[0]].lmn,t[t[x].ch[0]].sz+min(t[x].co?0:inf,min(t[x].top(),t[t[x].ch[1]].lmn+1)));
        t[x].rmn=min(t[t[x].ch[1]].rmn,t[t[x].ch[1]].sz+min(t[x].co?0:inf,min(t[x].top(),t[t[x].ch[0]].rmn+1)));
    }
    void rotate(int x){
        int y=t[x].fa,d=t[y].ch[1]==x;
        t[t[y].ch[d]=t[x].ch[!d]].fa=y;
        if(nrt(y)) t[t[x].fa=t[y].fa].ch[t[t[y].fa].ch[1]==y]=x;
        else t[x].fa=t[y].fa;
        t[t[x].ch[!d]=y].fa=x;
        pushup(y);
    }
    void splay(int x){
        int y,z;
        while(nrt(x)){
            y=t[x].fa,z=t[y].fa;
            if(nrt(y)){
                rotate((t[y].ch[0]==x)==(t[z].ch[0]==y)?y:x);
            }
            rotate(x);
        }
        pushup(x);
    }
    void access(int x){
    //    cout<<" access "<<x<<endl;
        for(reg y=0;x;y=x,x=t[x].fa){
            splay(x);
            if(y) t[x].dele(t[y].lmn+1);
            if(t[x].ch[1]) t[x].ins(t[t[x].ch[1]].lmn+1);
            t[x].ch[1]=y;
            pushup(x);
          //  cout<<" x "<<x<<" y "<<y<<endl;
         //   t[x].op();
        }
    }
    struct edge{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    void dfs(int x,int fa){
        t[x].sz=1;
        t[x].lmn=inf;t[x].rmn=inf;
        t[x].co=0;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            t[y].fa=x;
            dfs(y,x);
        }
    }
    int main(){
        rd(n);
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);
            add(x,y);add(y,x);
        }
        dfs(1,0);
        rd(q);
        int op;
        t[0].lmn=inf,t[0].sz=0;
        t[0].rmn=inf;t[0].co=233;
        while(q--){
            rd(op);rd(x);
            if(!op){
                access(x);splay(x);
                t[x].co^=1;
                pushup(x);
            //    t[x].op();
            }else{
                access(x);splay(x);
            //    t[x].op();
                printf("%d
    ",t[x].rmn<=n?t[x].rmn:-1);
            }
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/3/14 21:49:23
    */

    见着拆招,pushup不好处理,就直接记录lmn和rmn,lmn用于access更新set,rmn用于查询答案。

    如果要换根,还要考虑swap(lmn,rmn)

  • 相关阅读:
    滚动计算基础知识
    Javascript继承
    提取URL字符串的搜索字符串中的参数
    C++编程练习(13)----“排序算法 之 堆排序“
    常见网络端口 和 常见网络协议
    TCP协议中的三次握手和四次挥手(图解)
    C++编程练习(14)-------“单例模式”的实现
    编程练习------C/C++分别实现字符串与整数的转换
    IPv4地址学习总结
    C/C++中的联合体
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10534759.html
Copyright © 2011-2022 走看看