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\n",(*S.begin()).first);
        }
    }
    return 0;
}

  

posted @ 2016-12-28 16:57  北北北北屿  阅读(56)  评论(0编辑  收藏