zoukankan      html  css  js  c++  java
  • P3806 【模板】点分治1

    P3806 【模板】点分治1

    Q:多次询问(可离线)树上距离为k的点对是否存在

    A:淀粉质点分治

    复杂度:$O(nlogn)$

    对于每次分治,我们先找到这棵(子)树的重心$rt$

    我们发现,每次询问可分为2种情况。

    1.距离为$k$的两个点之间的路径经过$rt$

    2.两个点都在这棵(子)树的子树上

    每层分治我们都只处理第1种情况

    第2种情况就对这棵树的每个子树进行分治以转化为第1种

    具体怎么实现呢

    我们用$d[i]$表示子树$u_{1}$~$u_{j-1}$与$rt$距离为$i$的点是否存在

    每次遍历一个子树$u_{j}$,用$pos$存下每个点与$rt$的距离,然后在$d$中匹配看是否有符合条件的。

    再把$pos$存到$d$中

    分治结束时记得把$d$清空


    $siz[i]$:(子)树$i$的节点数(大小)

    $dis[i]$:点$i$与$rt$的距离

    $mxd[i]$:最大子树的大小

    $pos[i]$:储存遍历子树$j$每个点的距离

    $d[i]$:储存子树$1$~$j-1$的是否存在与$rt$距离$i$的点


    很丑的code.....

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    inline int max(int &a,int &b){return a>b?a:b;}
    void read(int &x){
        char c=getchar();x=0;
        while(c<'0'||c>'9') c=getchar();
        while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
    }
    #define N 10005
    #define K 10000005 
    int n,m,rt,sum,siz[N],dis[N],mxd[N];
    int pos[K],d[K],q[N],ask[105],ok[105];
    int cnt,hd[N],nxt[N<<1],ed[N],poi[N<<1],val[N<<1];
    bool vis[N];
    inline void adde(int x,int y,int v){
        nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt;
        ed[x]=cnt; poi[cnt]=y; val[cnt]=v;
    }
    void grt(int x,int fa){//找重心
        siz[x]=1; mxd[x]=0;
        for(int i=hd[x];i;i=nxt[i]){
            int to=poi[i];
            if(to==fa||vis[to]) continue;
            grt(to,x);
            siz[x]+=siz[to];
            mxd[x]=max(mxd[x],siz[to]);
        }mxd[x]=max(mxd[x],sum-siz[x]);
        if(mxd[x]<mxd[rt]) rt=x;
    }
    void gdis(int x,int fa){//找每个点的距离
        pos[++pos[0]]=dis[x];
        for(int i=hd[x];i;i=nxt[i]){
            int to=poi[i];
            if(to==fa||vis[to]) continue;
            dis[to]=dis[x]+val[i];
            gdis(to,x);
        }
    }
    void calc(int x){
        q[0]=0; d[0]=1;
        for(int i=hd[x];i;i=nxt[i]){
            int to=poi[i];
            if(vis[to]) continue;
            pos[0]=0; dis[to]=val[i];
            gdis(to,x);
            for(int j=1;j<=pos[0];++j)
                for(int k=1;k<=m;++k)
                    if(ask[k]>=pos[j])
                        ok[k]|=d[ask[k]-pos[j]];
            for(int j=1;j<=pos[0];++j)
                q[++q[0]]=pos[j],d[pos[j]]=1;
        }
        for(int i=1;i<=q[0];++i) d[q[i]]=0;//每次只清空用过的空间,memset很慢
    }
    void solve(int x){
        vis[x]=1; calc(x);
        for(int i=hd[x];i;i=nxt[i]){
            int to=poi[i];
            if(vis[to]) continue;
            rt=0; sum=siz[to];
            grt(to,x); solve(rt);//下一步:每棵子树的重心
        }
    }
    int main(){
        read(n);read(m);
        for(int i=1,q1,q2,q3;i<n;++i){
            read(q1),read(q2),read(q3);
            adde(q1,q2,q3),adde(q2,q1,q3);
        }
        for(int i=1;i<=m;++i) read(ask[i]);
        mxd[rt=0]=n+1; sum=n; grt(1,0); solve(rt);
        for(int i=1;i<=m;++i) puts(ok[i]?"AYE":"NAY");
        return 0;
    }
  • 相关阅读:
    spring security使用数据库管理用户权限
    ubuntu安装配置jdk tomcat mysql ...
    64位虚拟机安装64位ubuntu出现问题
    maven pom文件结构详解
    Maven3下的java web项目
    数据库分页和使用jstl标签替换分页的jsp代码
    servlet生命周期
    图片校验码的生成
    HttpSessionListener和HttpSessionBindingListener监听session的销毁
    perl 处理特殊字符
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10508088.html
Copyright © 2011-2022 走看看