1. 程式人生 > >bzoj1095動態點分治

bzoj1095動態點分治

寫在正文前的例行吐槽:

我終於,終於,終於也是寫過動態點分治的人了。。。

加上動態dp和動態樹是不是就可以集齊套裝召喚神龍了呢。。(思考ing)

動態點分治:

你會碰到一類問題。。有多個修改詢問之類的操作。。可以用一次點分治回答一次詢問

這時候我們可以把點分樹建出來。。。

點分樹有一些性質:

1.樹高不超過log層。(顯然吧orz。。。)

2.在進行點分治時,套路就是從當前點出發向外擴充套件,直到碰到已經訪問過的點為止,然後這樣可以處理出所有從這個點出發的、還未被統計過的鏈。我們將從點i出發擴充套件到的區域稱為它的管轄範圍(隨便yy的),顯然每個點的管轄範圍都是一定的。

而在點分樹上,一個點的兒子們管轄的範圍絕對沒有重合。

然後就在每個點上維護一下它管轄的範圍的資訊,且兒子的資訊基本上都會對父親產生影響,所以每次修改時暴力往上一個個修改父親的資訊直到走到點分樹的根為止,修改一次是(log n*修改複雜度)的。而因為在點分治合併時往往要去掉同一個子樹內的重複資訊,所以像bzoj1095一樣在每個點上維護它的所有兒子的資訊也比較常見了。(兒子們分開了避免合併出問題)

bzoj1095具體題解:

在每個點上記錄:

它的管轄範圍內所有黑點到它點分樹上父親的距離(堆1)

它的每個兒子的堆1的堆頂(堆2)

於是:每個點管轄範圍內經過它的最長鏈就是它堆2中取出最大值和次大值相加,然後把每個點的這個資訊扔到ans堆裡,查詢時直接找出ans堆的堆頂就好了。

其實參考一下本來點分的過程就發現了神奇的事情:

對於每個點,

用陣列存下它在點分樹上兒子的管轄範圍內所有黑點到它的距離 ,然後取出它的最大值->距離會修改,就用堆存(堆1)

每個兒子要分開存,不然合併資訊時會出現同一個子樹裡的合併在一起的情況,而每個兒子的最大值可能會被修改,要求所有兒子的最大值的最大值和次大值(。。。)->本來是兩個int記錄一下的東西,因為動態了又變成堆(堆2)

真是妙不可言啊。。。

當然,因為這個堆還要支援刪除,而我懶得手寫堆,也不是很想在找最大值和次大值的時候pop兩次再push回來,所以直接用了multiset,常數當然是上天了的。。。在luogu裡T了一個點,bzoj上過了。為了程式碼短而成為了鹹魚。。。orz。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (register int x=y; x<=z; x++)
#define downrep(x,y,z) for (register int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (register int x=hed[y]; ~x; x=edge[x].nex)
inline int read(){
    int x=0; int w=0; char ch=0;
    while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
    while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return w? -x:x;
}
const int N=100005;
const int Maxlg=17;
int tin[N],tout[N],tot,dep[N],f[N][Maxlg+1],fa[N],n,m,nedge,hed[N];
int nsz,root,sz[N],maxson[N],vis[N],col[N];
multiset<int> s1[N],s2[N],ans;
char s[15];
struct Edge{ int to,nex; }edge[N<<1];
void addedge(int a,int b){ edge[nedge].to=b; edge[nedge].nex=hed[a]; hed[a]=nedge++; }
void getdep(int k,int pre){
    tin[k]=++tot;
    repedge(i,k){
        int v=edge[i].to; if (v==pre) continue;
        dep[v]=dep[k]+1; f[v][0]=k;
        getdep(v,k);
    }tout[k]=tot;
}
bool isancestor(int x,int y){ return ((tin[x]<=tin[y])&&(tout[y]<=tout[x])); }
int getlca(int x,int y){
    if(isancestor(x,y)) return x;
    if(isancestor(y,x)) return y;
    downrep(i,Maxlg,0)if (!isancestor(f[x][i],y)) x=f[x][i];
    return f[x][0];
}
int dis(int x,int y){ int xylca=getlca(x,y); return (dep[x]+dep[y]-2*dep[xylca]); }
void getsz(int k,int pre){
    ++nsz; repedge(i,k){ int v=edge[i].to; if ((vis[v])||(v==pre)) continue; getsz(v,k); }
}
void getroot(int k,int pre){
    sz[k]=1; maxson[k]=0;
    repedge(i,k){
        int v=edge[i].to; if ((vis[v])||(v==pre)) continue;
        getroot(v,k); sz[k]+=sz[v]; maxson[k]=max(maxson[k],sz[v]);
    }
    maxson[k]=max(maxson[k],nsz-sz[k]);
    if ((!root)||(maxson[k]<maxson[root])) root=k;
}
void dfs(int k,int pre,int K,int d){
    s1[K].insert(d); 
    repedge(i,k){ int v=edge[i].to; if ((v==pre)||(vis[v])) continue; dfs(v,k,K,d+1); }
}
int Ans(int x){
    if (s2[x].begin()==s2[x].end()) return -1;
    int cnt=0; int res=0;
    for(multiset<int>::iterator i=(--s2[x].end()); ; i--){
      if (cnt<2) ++cnt,res+=(*i); else break;
      if (i==s2[x].begin()) break;
    }
    return (cnt>=2)? res:((cnt==1)? 0:(-1));
}
void getans(int k,int f){
    fa[k]=f; vis[k]=1; s2[k].insert(0);
    repedge(i,k){
        int v=edge[i].to; if (vis[v]) continue;
        nsz=0; getsz(v,k); root=0; getroot(v,k);
        dfs(v,k,root,1); 
        s2[k].insert(*(--s1[root].end()));
        getans(root,k);
    }
}
void Upd(int x){
    col[x]^=1; 
    if (!col[x]){
        ans.erase(ans.lower_bound(Ans(x)));
        s2[x].erase(s2[x].lower_bound(0));
        ans.insert(Ans(x));
        for(int i=x; fa[i]; i=fa[i]){
            int y=dis(x,fa[i]); int yy=(*(--s1[i].end()));
            s1[i].erase(s1[i].lower_bound(y));
            if (y==yy){ 
               ans.erase(ans.lower_bound(Ans(fa[i])));
               s2[fa[i]].erase(s2[fa[i]].lower_bound(y));
               if (s1[i].begin()!=s1[i].end()) s2[fa[i]].insert(*(--s1[i].end()));
               ans.insert(Ans(fa[i]));
            }
        }
    }
    if (col[x]){
        ans.erase(ans.lower_bound(Ans(x)));
        s2[x].insert(0);
        ans.insert(Ans(x));
        for(int i=x; fa[i]; i=fa[i]){
            int y=dis(x,fa[i]); 
            ans.erase(ans.lower_bound(Ans(fa[i])));
            if (s1[i].begin()!=s1[i].end()) 
            s2[fa[i]].erase(s2[fa[i]].lower_bound(*(--s1[i].end())));
            s1[i].insert(y);
            s2[fa[i]].insert(*(--s1[i].end())); 
            ans.insert(Ans(fa[i]));
        }
    }
}
int main(){
    scanf("%d",&n); nedge=0; ms(hed,-1,hed);
    rep(i,1,n-1){ int a,b; scanf("%d%d",&a,&b); addedge(a,b); addedge(b,a); }
    f[1][0]=1; getdep(1,1); rep(j,1,Maxlg) rep(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
    nsz=n; root=0; getroot(1,1); getans(root,0); 
    rep(i,1,n){ ans.insert(Ans(i)); col[i]=1; }
    scanf("%d",&m);
    rep(i,1,m){
        int x; scanf("%s",&s);
        if (s[0]=='C'){ scanf("%d",&x); Upd(x);	}
        if (s[0]=='G') printf("%d\n",(*(--ans.end())));
    }
    return 0;
}