动态点分治

好吧,我想说,动态点分治思路好理解,但打起来真让人心累。

所谓动态点分治,就是点分治在线修改和查询。

此时,我们构造一个点分树,先找整棵树的重心,以他为根,将他和每个子树的重心连边,以此类推。

对于每个重心,我们维护一些需要的信息

我们在修改的时候,只需要沿着点分树往上跳修改信息就好了。

动态点分树到这里就讲完了,但真正的难点是你的维护和修改。

例题1:P2056 [ZJOI2007]捉迷藏

网址:https://www.luogu.com.cn/problem/P2056

这题被号称是最水的动态点分治,但是我看了两个小时才明白,然后又打了一个小时,呜呜。

我的代码借鉴了https://www.cnblogs.com/LadyLex/p/8006488.html

可是哪位大佬太强,两三句就说完了,我这里算是对他的补充说明吧。

找最长链,那么我们需要维护最长链和次长链,但是由于数据可以被修改,所以不能只维护这两条。

定义一个堆h2[i]用来维护以i为重心的树上的黑店到i的距离。

但是我们不可能每次修改都重新遍历整棵树重新计算h2吧,所以再定义h1[i]用于维护以i为重心的树上的黑点到i在点分树上的父亲的距离。

这样一来,h2里面只用存储它的每个子树的h1.top()了,哈哈哈。

但我们要求的是求出整棵树的最大值,那不简单,再来一个堆h3呗。

h3只用管每个h2的最大和次大之和最大就好了。

考虑到修改的时候需要删除队列里的值,那么我们给每个堆定义两个优先队列,一个负责存进的,一个负责存删的。

当要删的元素不在队首时,我们删不到他,但他也不影响结果。一旦他来到队首影响结果的时候,我们就可以删除他了。

在修改的时候,不管三七二十一,应为此次修改有可能影响到答案,所以将他的一切信息删除,即从h3中剔除h2的最长+次长,从h2中剔除h1的最长。

对这个值进行修改,然后再把h1的最长加入h2,把h2的最长+次长加入h3。

这道题到这就算讲完了,看代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+100;
#define inf 1e9
inline int read(){
    int x=0,f=1;
    char c=getchar();
    while(c>'9'||c<'0'){
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+c-'0';
        c=getchar();
    }
    return x*f;
}
inline char getc(){
    char c=getchar();
    while(c<'A'||c>'Z')c=getchar();
    return c;
}
struct heap{
    priority_queue<int>q1,q2;
    inline void push(int x){q1.push(x);}
    inline void erase(int x){q2.push(x);}
    inline int top(){
        while(q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop();
        return q1.top();
    }
    inline void pop(){
        while(q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop();
        q1.pop();
    }
    inline int top2(){
        int tmp=top();pop();
        int ret=top();push(tmp);
        return ret;
    }
    inline int size(){
        return q1.size()-q2.size();
    }
}h1[maxn],h2[maxn],h3;
int n,beg[maxn],nex[maxn],to[maxn],e;
void add(int x,int y){
    e++;nex[e]=beg[x];
    beg[x]=e;to[e]=y;
}
int dep[maxn],f[maxn][25];
void build(int x,int fa){
    dep[x]=dep[fa]+1;
    f[x][0]=fa;
    for(int i=1;i<=20;i++)
        f[x][i]=f[f[x][i-1]][i-1];
    for(int i=beg[x];i;i=nex[i]){
        int t=to[i];
        if(t==fa)continue;
        build(t,x);
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=20;i>=0;i--)
        if(dep[x]-(1<<i)>=dep[y])x=f[x][i];
    if(x==y)return x;
    for(int i=20;i>=0;i--)
        if(f[x][i]!=f[y][i]){
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}
int sz[maxn],son[maxn],vis[maxn];
int mx,rt,size;
void getrt(int x,int fa){
    sz[x]=1,son[x]=0;
    for(int i=beg[x];i;i=nex[i]){
        int t=to[i];
        if(t==fa||vis[t])continue;
        getrt(t,x);
        sz[x]+=sz[t];
        if(son[x]<sz[t])son[x]=sz[t];
    }
    if(son[x]<size-sz[x])son[x]=size-sz[x];
    if(son[x]<mx)mx=son[x],rt=x;
}
int las[maxn];
int dis(int a,int b){
    return dep[a]+dep[b]-2*dep[lca(a,b)];
}
void stk(int x,int fa,int v){
    h1[rt].push(dis(x,v));
    for(int i=beg[x];i;i=nex[i]){
        int t=to[i];
        if(t==fa||vis[t])continue;
        stk(t,x,v);
    }
} 
void divide(int x,int fa){
    las[x]=fa;
    vis[x]=1;
    h2[x].push(0);
    int siz=size;
    for(int i=beg[x];i;i=nex[i]){
        int t=to[i];
        if(vis[t])continue;
        if(sz[t]>sz[x])size=siz-sz[x];
        else size=sz[t];
        rt=0,mx=inf,getrt(t,0),stk(rt,0,x);
        h2[x].push(h1[rt].top());
        divide(rt,x);
    }
    if(h2[x].size()>1)h3.push(h2[x].top()+h2[x].top2());
}
int state[maxn],cnt,q;
void turnoff(int x){
    if(h2[x].size()>1)h3.erase(h2[x].top()+h2[x].top2());
    h2[x].push(0);
    if(h2[x].size()>1)h3.push(h2[x].top()+h2[x].top2());
    int tmp=las[x],p=x;
    while(tmp){
        if(h2[tmp].size()>1)h3.erase(h2[tmp].top()+h2[tmp].top2());
        if(h1[p].size())h2[tmp].erase(h1[p].top());
        h1[p].push(dis(x,tmp));
        h2[tmp].push(h1[p].top());
        if(h2[tmp].size()>1)h3.push(h2[tmp].top()+h2[tmp].top2());
        p=tmp;tmp=las[tmp];
    }
}
void turnon(int x){
    if(h2[x].size()>1)h3.erase(h2[x].top()+h2[x].top2());
    h2[x].erase(0);
    if(h2[x].size()>1)h3.push(h2[x].top()+h2[x].top2());
    int tmp=las[x],p=x;
    while(tmp){
        if(h2[tmp].size()>1)h3.erase(h2[tmp].top()+h2[tmp].top2());
        h2[tmp].erase(h1[p].top());
        h1[p].erase(dis(x,tmp));
        if(h1[p].size())h2[tmp].push(h1[p].top());
        if(h2[tmp].size()>1)h3.push(h2[tmp].top()+h2[tmp].top2());
        p=tmp;tmp=las[tmp];
    }
}
int main(){
    n=read();
    int x,y;
    for(int i=1;i<n;i++){
        x=read(),y=read();
        add(x,y),add(y,x);
    }
    build(1,0);
    mx=inf,rt=0,size=n;
    getrt(1,0);
    divide(rt,0);
    cnt=n;
    q=read();
    while(q--){
        char opt;
        opt=getc();
        if(opt=='C'){
            int x;
            x=read();
            if(state[x])cnt++,turnoff(x);
            else cnt--,turnon(x);
            state[x]^=1;
        }else{
            if(cnt<2)printf("%d
",cnt-1);
            else printf("%d
",h3.top());
        }
    }
    return 0;
}

深深地感到自己的渺小……

原文地址:https://www.cnblogs.com/syzf2222/p/12289508.html