poj1741 Tree,平衡树,启发式合并

楼教主男人八题之一。
点分治看腻了吧。来点新鲜的。

关于启发式合并,我的上篇博客已经写了一些,请移步 这儿。


这题和hdu4812一样,也是询问 是否存在/有多少个/各种最小 满足某条件的树的路径。
树的路径问题在这里可化为树上一对点的问题。
同样,每个叶节点建一个包含自己的平衡树。
dfs回溯时,非叶节点选取含点最多的子节点的平衡树作为自己的平衡树,将其他的子节点的平衡树暴力合并到这个树上。
同时查询这个子节点中小于给定要求长度的节点的个数,更新答案即可。
注意暴力合并时,要先询问再合并,否则本树上的节点会有重复计算。

由于每个节点的插入次数小于O(logn),总插入次数不超过O(nlogn)。
用treap进行插入、查询复杂度为O(logn),因此总复杂度为O(nlognlogn)。
不过不进行删除操作的话,需要O(nlogn)的空间。
实际效果不错,157ms。
#include
#include
#include
#include
using namespace std;
#define NN 10100

int tn;
struct treap{
    int l,r,fix,tot,val,cnt;
    void init(int v){
        l=r=0;
        fix=rand()*rand();
        tot=cnt=1;
        val=v;
    }
}t[NN*12];

void init_treap(){
    srand(1314);
    tn=0;
    t[0].cnt=t[0].tot=0;
    t[0].fix=-1000001000;
}


#define getot(p) \
do{\
    t[p].tot=t[p].cnt;\
    if (t[p].l) t[p].tot+=t[t[p].l].tot;\
    if (t[p].r) t[p].tot+=t[t[p].r].tot;\
}while(0);

/*
inline void getot(int p){
    t[p].tot=t[p].cnt;
    if (t[p].l) t[p].tot+=t[t[p].l].tot;
    if (t[p].r) t[p].tot+=t[t[p].r].tot;
}
*/

inline void rrot(int &p){
    int y=t[p].l;
    t[p].l=t[y].r;
    t[y].r=p;
    getot(p);
    p=y;
    getot(p);
}

inline void lrot(int &p){
     int y=t[p].r;
     t[p].r=t[y].l;
     t[y].l=p;
     getot(p);
     p=y;
     getot(p);
}
void insert(int val,int &p,int num=1){
     if (p==0) {
         p=++tn;
         t[p].init(val);
         t[p].cnt=t[p].tot=num;
         return;
     }
     t[p].tot+=num;
     if (val==t[p].val) {t[p].cnt+=num;}
     else if (valt[t[p].l].fix) rrot(p);
     }
     else {
          insert(val,t[p].r,num);
          if (t[p].fix>t[t[p].r].fix) lrot(p);
     }
     //getot(p);
}

int queryless(int val,int p){
    if (val==t[p].val) return t[t[p].l].tot+t[p].cnt;
    else if (valma) {ma=tot[v];son[u]=v;sw[u]=w[e];}
            tot[u]+=tot[v];
        }
    }
}

void merge(int &ru,int rv,int du,int dv){
    insert(t[rv].val+dv-du,ru,t[rv].cnt);
    if (t[rv].l) merge(ru,t[rv].l,du,dv);
    if (t[rv].r) merge(ru,t[rv].r,du,dv);
}

void query(int &ru,int rv,int du,int dv){
    int tmp,val;
    val=k-t[rv].val-du-dv;
    tmp=queryless(val,ru);
    ans+=tmp*t[rv].cnt;
    if (t[rv].l) query(ru,t[rv].l,du,dv);
    if (t[rv].r) query(ru,t[rv].r,du,dv);
}

void dfs2(int u,int fa,int dd){
    int e,v;
    if (son[u]==-1){
        root[u]=++tn;t[tn].init(0);
        dis[u]=dd;
        return;
    }
    dfs2(son[u],u,sw[u]);
    root[u]=root[son[u]];
    dis[u]=dis[son[u]];
    ans+=queryless(k-dis[u],root[u]);
    insert(-dis[u],root[u],1);
    for(e=fi[u];e!=-1;e=ne[e]){
        v=to[e];
        if (v!=fa&&v!=son[u]){
            dfs2(v,u,w[e]);
            query(root[u],root[v],dis[u],dis[v]);
            merge(root[u],root[v],dis[u],dis[v]);
        }
    }
    dis[u]+=dd;
}

int main(){
    //freopen("1741in.txt","r",stdin);
    int a,b,c,i;
    while(scanf("%d%d",&n,&k)&&(n||k)){
        te=0;
        memset(fi,-1,sizeof(fi));
        for(i=1;i






你可能感兴趣的:(POJ,数据结构,启发式合并)