zoukankan      html  css  js  c++  java
  • 动态点分治

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

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

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

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

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

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

    例题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;
    }

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

  • 相关阅读:
    将font-size设置为 12px 以下,Chrome浏览器只能显示12px怎么办?
    如何创建.gitignore文件,忽略不必要提交的文件
    linux中将网速设置成10baseT/Half用于测试
    点击checkbox后满足条件才改变状态
    使用parted和kpartx 来对sdcard镜像进行分区调整,顺便用一下losetup
    linux添加具有root权限的管理员账号
    windows下获取系统的UUID
    pip修改镜像源
    linux中umount和mount
    mac安装brew
  • 原文地址:https://www.cnblogs.com/syzf2222/p/12289508.html
Copyright © 2011-2022 走看看