BZOJ1095 动态点分治(点分树)

杀马特。学长 韩版系。学妹 提交于 2020-03-04 15:07:36

题意:

操作1.修改一个点的颜色(黑白互换)

操作2.询问所有黑色点之间最远距离

 

点分树:当我们可以形如点分治一样的统计答案,即每次确定一个重心,然后计算他们子树之间的贡献和得出答案的时候

我们可以将每个区域的重心作为其所有子树的重心的父亲,构成一颗新的树,显然这棵树的深度不会超过logn

每次对于单点(边)更新的时候,只要对其所有的父亲更新,就只需要更新log个点,这样的数据结构就是点分树

 

对于本题来说,最终的答案是在每个点作为链上一个点的时候,找每个点出发的最长链和次长链的和的最大值

所以用一个堆A维护每个点在点分树中子树下所有的点到这个点父亲的距离

再用一个堆B维护每个点所有儿子点的堆A的最大值,即每条链的最长的长度

最后用一个堆C维护每个点的最长值 + 次长值的大小

 

tips:

1.树上两两之间的点的距离可以rmq + ST表预处理之后O(1)查询,注意转化成序列不是dfs序,具体看代码

2.做一个供删除的优先队列,可以用两个优先队列A,B,一个正常用,删除操作就是把元素加入B,当AB顶部相同的时候一起弹出

 

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <bitset>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x)  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
const double PI = acos(-1.0);
const double eps = 1e-9;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
struct heap{
    priority_queue<int>A,B;
    void push(int x){A.push(x);}
    void del(int x){B.push(x);}
    void init(){
        while(!B.empty() && A.top() == B.top()){
            A.pop(); B.pop();
        }
    }
    int top(){
        init();
        if(A.empty()) return 0;
        return A.top();
    }
    int size(){
        return A.size() - B.size();
    }
    int Maxdis(){
        if(size() < 2) return 0;
        int x = top(); A.pop();
        int y = top(); A.push(x);
        return x + y;
    }
};
struct Edge{
    int to,next;
}edge[maxn << 1];
int head[maxn],tot;
void init(){
    for(int i = 0 ; i <= N ; i ++) head[i] = -1;
    tot = 0;
}
void add(int u,int v){
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
int dep[maxn];
int id[maxn],pos[maxn],cnt;
void dfsinit(int u,int la){
    id[++cnt] = dep[u];
    pos[u] = cnt;
    for(int i = head[u]; ~i ; i = edge[i].next){
        int v = edge[i].to;
        if(v == la) continue;
        dep[v] = dep[u] + 1;
        dfsinit(v,u);
        id[++cnt] = dep[u]; 
    }
}
const int SP = 20;
int MIN[maxn][SP],mm[maxn];
void initRMQ(int n,int b[]){
    for(int i = 1; i <= n ; i ++){
        for(int j = 0 ; j < SP; j ++){
            MIN[i][j] = INF;
        }
    }
    mm[0] = -1;
    for(int i = 1; i <= n; i ++){
        mm[i] = ((i & (i - 1)) == 0)?mm[i - 1] + 1:mm[i - 1];
        MIN[i][0] = b[i];
    }
    for(int j = 1; j <= mm[n]; j ++){
        for(int i = 1; i + (1 << j) - 1 <= n; i ++){
            MIN[i][j] = min(MIN[i][j - 1],MIN[i + (1 << (j - 1))][j - 1]);
        }
    }
}
int rmq(int x,int y){
    if(x > y) swap(x,y);
    int k = mm[y - x + 1];
    return min(MIN[x][k],MIN[y - (1 << k) + 1][k]);
}
int getdis(int x,int y){
    return dep[x] + dep[y] - 2 * rmq(pos[x],pos[y]);
}
struct dtnode{
    int fa;
    heap Q,P;
    int Maxdis(){
        return Q.top();
    }
    int Maxline(){
        return P.Maxdis();
    }
}dt[maxn];
heap fans;
int root,max_part,SUM;
int size[maxn],vis[maxn];
int dis[maxn];
void dfs_root(int u,int la){
    size[u] = 1; int heavy = 0;
    for(int i = head[u]; ~i ; i = edge[i].next){
        int v = edge[i].to;
        if(v == la || vis[v]) continue;
        dfs_root(v,u);
        heavy = max(heavy,size[v]);
        size[u] += size[v];
    }
    if(max_part > max(heavy,SUM - heavy)){
        max_part = max(heavy,SUM - heavy);
        root = u;
    }
}
void dfs(int u,int la){
    dis[u] = getdis(u,dt[root].fa);
    dt[root].Q.push(dis[u]);
    for(int i = head[u]; ~i ; i = edge[i].next){
        int v = edge[i].to;
        if(v == la || vis[v]) continue;
        dfs(v,u);
    }
}
int divide(int t,int la){
    max_part = INF;
    root = t; 
    dfs_root(t,-1); 
    int now = root;
    dt[root].fa = la; dt[root].P.push(0);
    if(~la) dfs(root,-1);
    vis[root] = 1;
    for(int i = head[now]; ~i ; i = edge[i].next){
        int v = edge[i].to;
        if(vis[v]) continue;
        SUM = size[v];
        v = divide(v,now);
        dt[now].P.push(dt[v].Maxdis());
    }
    if(dt[now].P.size() >= 2)fans.push(dt[now].Maxline());
    return now;
}
int use[maxn];
int main(){
    Sca(N); init();
    for(int i = 1; i < N ; i ++){
        int u = read(),v = read();
        add(u,v); add(v,u);
    }
    dfsinit(1,-1); initRMQ(cnt,id);
    SUM = N; divide(1,-1);
    int num = N;
    Sca(M);
    while(M--){
        char op[3]; scanf("%s",op);
        if(op[0] == 'G'){
            if(num == 1) puts("0");
            else if(!num) puts("-1");
            else{
                Pri(fans.top());
            }    
        }else{
            int v = read(); int tmp = v;
            if(use[v]) num++;
            else num--;
            if(dt[v].P.size() >= 2) fans.del(dt[v].Maxline());
            if(use[v]) dt[v].P.push(0);
            else dt[v].P.del(0);
            if(dt[v].P.size() >= 2) fans.push(dt[v].Maxline());
            while(~dt[tmp].fa){
                int u = dt[tmp].fa;
                if(dt[u].P.size() >= 2) fans.del(dt[u].Maxline());
                if(dt[tmp].Q.size()) dt[u].P.del(dt[tmp].Maxdis());
                int d = getdis(v,u);
                if(use[v]) dt[tmp].Q.push(d);
                else dt[tmp].Q.del(d);
                if(dt[tmp].Q.size()) dt[u].P.push(dt[tmp].Maxdis());
                if(dt[u].P.size() >= 2) fans.push(dt[u].Maxline());
                tmp = u;
            }
            use[v] ^= 1;
        }
    }
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!