bzoj1095 (点分树)

题目大意:n个节点的树,m次操作,每次将白点变黑,将黑点变白,或询问最远黑点对的距离。

若无修改,可直接树形dp或点分求即可,加上修改的话就要用到点分树了(orz括号序列的做法)。。。考虑没修改时点分治的做法为对每个root,最远点对即为不同子树上最远和次远黑点的距离之和,所以对于点分树的每个结点 X 用个堆S维护X的每棵子树最远黑点距离,以及一个堆T维护 X 所在子树的每个黑点与上一层节点 fa[x] 的距离。然后在加个堆ans维护每个节点的答案即可。。

这里用的multiset来代替的堆,写法较容易,但时间也慢得飞起。。

 

#include
#include
#include
#include
#include
using namespace std;
vectorg[100010];
int son[100010],siz[100010],ma[100010],vis[100010],root,A[100010];
int dis[100010][20],dep[100010],fa[100010][20];
void dfsroot(int u,int f,int sum){
     int i,v;
     son[u]=0;
     siz[u]=1;
     for(i=0;is[100010],t[100010],ans;
multiset::iterator it;
int max1(int u){
    if(t[u].size()==0) return -1;
    it=t[u].end();
    it--;
    return *it;
}
int max2(int u){
    if(s[u].size()<2) return -1;
    it=s[u].end();
    it--;
    int a=*it;
    it--;
    return a+*it;
}
void update(int u){
    int i,f,ff;
    for(i=dep[u];i;i--){
        f=fa[u][i];
        ff=fa[u][i-1];
        if(i==dep[u]){
            if(max2(f)!=-1) ans.erase(ans.find(max2(f)));
            if(A[u]) s[f].erase(0);
            else s[f].insert(0);
            if(max2(f)!=-1) ans.insert(max2(f));
        }
        if(ff){
            if(max2(ff)!=-1) ans.erase(ans.find(max2(ff)));
            if(max1(f)!=-1) s[ff].erase(s[ff].find(max1(f)));
            if(A[u]) t[f].erase(t[f].find(dis[u][i-1]));
            else t[f].insert(dis[u][i-1]);
            if(max1(f)!=-1) s[ff].insert(max1(f));
            if(max2(ff)!=-1) ans.insert(max2(ff));
        }
    }
}
int main(){
    int i,n,a,b,m;
    char c[10];
    scanf("%d",&n);
    for(i=1;i

 

你可能感兴趣的:(点分树,bzoj1095,点分树)