• BZOJ 1095: [ZJOI2007]Hide 捉迷藏


    Description

    一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离.

    Sol

    动态点分治.

    动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的...

    这样的树一共有 (logn) 层,每个节点维护一些信息.

    s1[] 所有子节点到该节点的父重心,也就是上一个重心,所有距离的集合,需要满足插入删除询问最大值的操作,这里我直接用的multiset.

    s2[] 所有子重心,就是下面一层的重心,到这个点的最大值分别是多少,需要满足插入删除询问最大值的操作,这里我直接用set.

    S答案集合,过所有重心的最长链的集合,就是所有子重心到他的最大值+次大值,需要满足插入删除询问最大值的操作,这里我直接用set.

    再加上一个 (O(1)) LCA来求一下距离.

    这样第一次预处理的时候处理完所有事情,数据修改的时候呢...我的做法比较蠢但是好写,不用考虑那么多乱七八糟的东西..

    直接求出整个链,因为一个点对下面的点是没有贡献的,直接向上找出来这一条由重心连成的链.

    然后先删掉所有这个节点可能产生的贡献,修改,再重新统计这些节点的最大值..插入同理...

    这样复杂度就变成了 (O(nlog^2n)) 数据结构有一个 (log) ,点分治有一个 (log) 修改也是 (log^2) 的

    打着打着发现自己代码到了6K...其实很大一部分都是调试信息...

    Code

    /**************************************************************
        Problem: 1095
        User: BeiYu
        Language: C++
        Result: Accepted
        Time:31445 ms
        Memory:78796 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
     
    #define debug(a) cout<<#a<<"="<<a<<" "
    #define mpr make_pair
    typedef pair< int,int > pr;
    const int N = 1e5+50;
    const int M = 25;
     
    int n,m,k,rt,cw;
    vector< pr > g[N];
    int t[N],sz[N],ud[N],cl[N],frt[N];
     
    set< pr,greater< pr > > S;
    multiset< int,greater< int >  > s1[N];
    set< pr,greater< pr > > s2[N]; 
     
    inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
    inline char getc(char ch=getchar()) { while(ch>'Z' || ch<'A') ch=getchar();return ch; }
     
    void Print(set< pr,greater< pr > > &S) {
        cout<<"--------start------------"<<endl;
        for(set< pr >::iterator i=S.begin();i!=S.end();i++) 
            cout<<"("<<(*i).first<<" "<<(*i).second<<") ";
        cout<<endl<<"----------over-----------"<<endl;
    }
    void Print(multiset< int,greater< int > > &S) {
        cout<<"--------start------------"<<endl;
        for(multiset< int >::iterator i=S.begin();i!=S.end();i++) 
            cout<<(*i)<<" ";
        cout<<endl<<"----------over-----------"<<endl;
    }
    void SuperPrint() {
        for(int i=1;i<=n;i++) cout<<frt[i]<<" ";cout<<endl;
         
        for(int i=1;i<=n;i++) cout<<i<<endl<<"--> s1[]"<<endl,Print(s1[i]),cout<<"--> s2[]"<<endl,Print(s2[i]);
         
        cout<<"--> S"<<endl;
        Print(S);
    }
    void AddEdge(int fr,int to,int w) { g[fr].push_back(mpr(to,w)); }
     
    struct Tree {
        int dp[N],ds[N],fw[N],ct;
        int lg[N<<1],rq[N<<1][M],pow2[M];
         
        void DFS(int u,int fa,int w) {
            fw[u]=++ct,dp[u]=dp[fa]+1,rq[ct][0]=u,ds[u]=w;
            for(int i=0,v;i<(int)g[u].size();i++)
                if((v=g[u][i].first)!=fa) DFS(v,u,w+g[u][i].second),rq[++ct][0]=u;
        }
        void init() {
            DFS(1,1,0);
            pow2[0]=1;for(int i=1;i<M;i++) pow2[i]=pow2[i-1]<<1;
            lg[0]=-1;for(int i=1;i<=ct;i++) lg[i]=lg[i>>1]+1;
            for(int j=1;j<M;j++) for(int i=1;i<=ct;i++) if(i+pow2[j]-1<=ct){
                int u=rq[i][j-1],v=rq[i+pow2[j-1]][j-1];
                if(dp[u]<dp[v]) rq[i][j]=u;else rq[i][j]=v;
            }
        }
        int Dis(int u,int v) {
            if(fw[u]>fw[v]) swap(u,v);
            int lg2=lg[fw[v]-fw[u]+1];
            int lca=dp[rq[fw[u]][lg2]]<dp[rq[fw[v]-pow2[lg2]+1][lg2]] ? rq[fw[u]][lg2] : rq[fw[v]-pow2[lg2]+1][lg2];
            return ds[u]+ds[v]-2*ds[lca];
        }
    }qt;
     
    int dis(int u,int v) { return qt.Dis(u,v); }
     
    void GetRoot(int u,int fa,int nn) {
        sz[u]=1,t[u]=0;
        for(int i=0,v;i<(int)g[u].size();i++)
            if((v=g[u][i].first)!=fa && !ud[v])
                GetRoot(v,u,nn),sz[u]+=sz[v],t[u]=max(t[u],sz[v]);
        t[u]=max(t[u],nn-sz[u]);
        if(t[u]<t[rt]) rt=u;
    }
     
    void GetDis(int u,int fa,int ff,int spf) {
        if(spf) s1[ff].insert(dis(u,spf));
        for(int i=0,v;i<(int)g[u].size();i++)
            if((v=g[u][i].first)!=fa && !ud[v]) GetDis(v,u,ff,spf);
    }
     
    pr Getv(int x) {
        if(s2[x].size()<2) return mpr(-1,-1);
        else return mpr((*s2[x].begin()).first+(*(++s2[x].begin())).first,x);
    }
     
    void GetAns(int u,int nn) {
        ud[u]=1;
        if(frt[u]) s1[u].insert(dis(u,frt[u]));s2[u].insert(mpr(0,u));
        for(int i=0,v;i<(int)g[u].size();i++) if(!ud[v=g[u][i].first]) {
            GetDis(v,u,u,frt[u]);
        }
        for(int i=0,v,ss;i<(int)g[u].size();i++) if(!ud[v=g[u][i].first]) {
            rt=0,ss=sz[u]>sz[v]?sz[v]:nn-sz[u];
            GetRoot(v,v,ss),frt[rt]=u,v=rt,GetAns(rt,ss);
            s2[u].insert(mpr(*s1[v].begin(),v));
        }
        S.insert(Getv(u));
    }
     
    //S All
    //s1 son->father'sfather
    //s2 sonmax
    void Modify(int x) {
        if(cl[x]) cw++;else cw--;
        vector< int > tmp;
        for(int i=x;i;i=frt[i]){ tmp.push_back(i); }
    //  for(int i=0;i<(int)tmp.size();i++) cout<<tmp[i]<<" ";cout<<endl;
        if(cl[x]) {
            for(int i=0;i<(int)tmp.size();i++) S.erase(Getv(tmp[i]));
            for(int i=0;i<(int)tmp.size();i++) {
    //          if(!i) s2[tmp[i]].erase(mpr(0,tmp[i]));
    //          else 
                if(i && !s1[tmp[i-1]].empty()) s2[tmp[i]].erase(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
            }
            for(int i=0;i<(int)tmp.size();i++) s1[tmp[i]].insert(dis(x,frt[tmp[i]]));
            for(int i=0;i<(int)tmp.size();i++) {
                if(!i) s2[tmp[i]].insert(mpr(0,tmp[i]));
                else s2[tmp[i]].insert(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
            }
            for(int i=0;i<(int)tmp.size();i++) S.insert(Getv(tmp[i]));
             
        }else {
            for(int i=0;i<(int)tmp.size();i++) S.erase(Getv(tmp[i]));
    //      cout<<"--> S"<<endl;Print(S);
            for(int i=0;i<(int)tmp.size();i++) {
                if(!i) s2[tmp[i]].erase(mpr(0,tmp[i]));
                else s2[tmp[i]].erase(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
            }
    //      cout<<"--> s2[1]"<<endl;Print(s2[1]);
    //      cout<<"--> s2[3]"<<endl;Print(s2[3]);
             
            for(int i=0;i<(int)tmp.size();i++) if(frt[tmp[i]]) s1[tmp[i]].erase(s1[tmp[i]].find(dis(x,frt[tmp[i]])));
            for(int i=0;i<(int)tmp.size();i++) {
    //          if(!i) s2[tmp[i]].insert(mpr(0,tmp[i]));
    //          else 
                if(i && !s1[tmp[i-1]].empty()) s2[tmp[i]].insert(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
            }
    //      cout<<"--> s2[1]"<<endl;Print(s2[1]);
            for(int i=0;i<(int)tmp.size();i++) S.insert(Getv(tmp[i]));
        }cl[x]^=1;
    }
     
    void init() {
        cw=n=in();
        for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=1,AddEdge(u,v,w),AddEdge(v,u,w);
    //  for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=in(),AddEdge(u,v,w),AddEdge(v,u,w);
        qt.init();
        t[0]=N;
        GetRoot(1,1,n);
        GetAns(rt,n);
    }
     
    int main() {
    //  freopen("in.in","r",stdin);
        init();
         
    //  SuperPrint();
         
    //  Print(S);
        for(int q=in();q--;) {
    //      cout<<"QAQ"<<endl<<endl;
            if(getc()=='C') {
                int x=in();Modify(x);
    //          cout<<"--> S"<<endl;Print(S);
    //          cout<<"--> s1[3]"<<endl;Print(s1[3]);
    //          cout<<"--> s2[3]"<<endl;Print(s2[3]);
    //          SuperPrint();
            }else {
                if(!cw) puts("-1");
                else if(cw==1) puts("0");
                else printf("%d
    ",(*S.begin()).first);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    CSS定位
    使用开源框架进行get,post提交
    使用httpclient框架分别用post,get方式提交
    C++ const_cast
    C++ 类继承 常量对象调用函数
    C++ 类继承 子类调用父类
    C++ explicit关键字
    C++ class入门
    C#检测耗时操作
    面向对象编程入门
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6230121.html
Copyright © 2020-2023  润新知