动态点分治学习笔记

动态点分治,其实就是在点分治的基础上,记录一下x在点分树中的祖先fa[x]是谁。修改的时候就沿着fa[x]一直修改到根就好了。
(点分树的定义:把点分治时每一层的重心之间连边,这就构成了一颗高度为logn的树)
这是原树:
这是点分树

例题: [ZJOI2007]捉迷藏
一句话题意:
一棵树,节点一开始全是黑色,每次可以修改一个点的颜色(黑变白,白变黑),或者询问树中最远的两个黑点的距离。
题解:
对于每个点x,我们记录它在点分树中的子节点 到 它在点分树中的父亲fa[x] 的 在原树中 距离的集合h1(两点全黑),显然对答案的贡献就是最长的两条链的和。
然而如果这两条链有重合呢???
所以我们再记录一个集合h2[x],表示它在点分树中的子节点v 的h1[v]中的最大值 的集合
显然对答案ans的贡献就是h2[x]中的最大值和次大值的和啦
那么选择什么数据结构来维护h1[],h2[],ans呢???
可以用堆啊!开两个堆,一个记录原始数据(h),一个记录已经删除的数据(del)
询问最大值时这样就好了
while(del.size()&&(h.top()==del.top())) h.pop(),del.top();
那次大值呢?这就交给读者你啦!

注意,这题极度卡常!!!
不要直接复制代码,你会T的
逃(

code:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define mst(arr,x) memset(arr,x,sizeof(arr))
const int INF = 0x7fffffff;
const int N   = 100009;
const int E   = 23;
int Read() {int ret=0,nag=1;char c=getchar();  while (c>'9'||c<'0') {if(c=='-') nag=-1;  c=getchar();}  while (c<='9'&&c>='0')    ret=(ret<<3)+(ret<<1)+c-'0',c=getchar();  return ret*nag;}
void Print(int x) {if(x<0) putchar('-'),x=-x;  if(x>9) Print(x/10);  putchar(x%10+'0');}
int n,T,head[N],to[N<<1],nxt[N<<1],CNT,val[N],cnt,dep[N],h[N][E+2];
int siz[N],weight[N],rt,SIZ,visit[N],FA[N];
struct node 
{
    priority_queue <int> h,del;int siz;
    void Insert(int x)  {h.push(x),siz++;}
    void Delete(int x)  {del.push(x),siz--;}
    int rk1()           {while(del.size()&&(h.top()==del.top()))    h.pop(),del.pop();return h.top();}
    int rk2()           {int t=rk1(),ret;h.pop(),ret=rk1(),h.push(t);return ret;}
}h1[N],h2[N],ans;
inline void Add_edge(int x,int y){CNT++,to[CNT]=y,nxt[CNT]=head[x],head[x]=CNT;}
inline void ins(int x){if(h2[x].siz>1) ans.Insert(h2[x].rk1()+h2[x].rk2());}
inline void del(int x){if(h2[x].siz>1) ans.Delete(h2[x].rk1()+h2[x].rk2());}
void dfs0(int x,int Fa)
{
    dep[x]=dep[Fa]+1;h[x][0]=Fa;
    for(int j=1;j<=E;j++)   h[x][j]=h[h[x][j-1]][j-1];
    for(int k=head[x];k;k=nxt[k])
    {
        int v=to[k];if(v==Fa) continue;
        dfs0(v,x);
    }
}
int lca(int x,int y)
{
    if(x==y) return x;
    if(dep[x]<dep[y])   swap(x,y);
    for(int j=E;j>=0;j--)  if(dep[h[x][j]]>=dep[y])   x=h[x][j];
    if(x==y) return x;
    for(int j=E;j>=0;j--)   if(h[x][j]!=h[y][j])    x=h[x][j],y=h[y][j];
    return h[x][0];
}
int d(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
void getroot(int x,int Fa)
{
    siz[x]=1,weight[x]=0;
    for(int k=head[x];k;k=nxt[k])
    {
        int v=to[k];if(v==Fa||visit[v]) continue;
        getroot(v,x),siz[x]+=siz[v],weight[x]=max(weight[x],siz[v]);
    }
    weight[x]=max(weight[x],SIZ-siz[x]);
    if(weight[rt]>weight[x])    rt=x;
}
void getdis(int x,int Fa,int y)
{
    h1[rt].Insert(d(x,y));
    for(int k=head[x];k;k=nxt[k])
    {
        int v=to[k];if(v==Fa||visit[v]) continue;
        getdis(v,x,y);        
    }
}
void Build(int x,int Fa)
{
    visit[x]=1,h2[x].Insert(0);
    getdis(x,0,Fa);
    for(int k=head[x];k;k=nxt[k])
    {
        int v=to[k];if(visit[v]) continue;
        weight[rt=0]=INF,SIZ=siz[v],getroot(v,0);
        FA[rt]=x;   int t=rt;Build(rt,x);
        h2[x].Insert(h1[t].rk1());
    }
    ins(x);
}
char opt[5];
void Modify0(int x)
{
    del(x),h2[x].Delete(0),ins(x);
    for(int i=x;FA[i];i=FA[i])
    {
        del(FA[i]);
        if(h1[i].siz)    h2[FA[i]].Delete(h1[i].rk1());
        h1[i].Delete(d(x,FA[i]));
        if(h1[i].siz)   h2[FA[i]].Insert(h1[i].rk1());
        ins(FA[i]);
    }
}
void Modify1(int x)
{
    del(x),h2[x].Insert(0),ins(x);
    for(int i=x;FA[i];i=FA[i])
    {
        del(FA[i]);
        if(h1[i].siz)   h2[FA[i]].Delete(h1[i].rk1());
        h1[i].Insert(d(x,FA[i]));
        if(h1[i].siz)   h2[FA[i]].Insert(h1[i].rk1());
        ins(FA[i]);
    }
}
int main ()
{
    cnt=n=Read();for(int i=1;i<=n;i++)  val[i]=1;
    for(int i=1;i<n;i++)   {int x=Read(),y=Read();Add_edge(x,y),Add_edge(y,x);}
    SIZ=n,weight[rt=0]=INF;getroot(1,0),dfs0(rt,0);
    Build(rt,0);
    T=Read();
    while(T--)
    {
        scanf("%s",opt);
        if(opt[0]=='C')
        {
            int x=Read();
            if(val[x])  Modify0(x),val[x]=0,cnt--;
            else Modify1(x),val[x]=1,cnt++;
        }
        else
        {
            if(cnt<2)   Print(cnt-1),puts("");
            else Print(ans.rk1()),puts("");
        }
        
    }
    return 0;
}
posted @ 2019-03-09 10:17  bjxdw  阅读(...)  评论(... 编辑 收藏