• 【模板】P3806点分治1


    【模板】P3806 【模板】点分治1

    很好的一道模板题,很无脑经典。

    讲讲淀粉质吧,很营养,实际上,点分治是树上的分治算法。根据树的特性,树上两点的路径只有一下两种情况:

    • 路径经过根((*))
    • 路径不经过根((**))

    显然对于((**))我们可以通过指定一个新的根使得((**))变成一个子问题。

    那么我们在处理的时候,分两种情况:

    • 处理自己各个子树之间的路径((-))
    • 各个子树之内的路径((--))

    显然((--))的问题可以通过递归((**))的子问题解决

    那么有什么用呢?

    考虑时间复杂度,我们指定新根时,若制定它的各自子树的重心,那么最多会递归(logn​)次。这是淀粉质的营养时间基数。

    那么,我们只需要设计在子树间进行统计答案的复杂度为(O(x)​)的算法,那么我们就可以做到(O(xlogn)​)的解决了。

    这道模板题是问我们是否存在路径长度为(k)的路径,我们直接开桶把一个点到指定的(rt)的距离存下来,之后直接查询即可,这样的时间复杂度是(O(n))

    总时间复杂度(O(nlogn))

    代码如下

    #include<bits/stdc++.h>
    
    using namespace std;
    #define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;++t)
    #define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
    #define ERP(t,a) for(register int t=head[a];t;t=e[t].nx)
    #define Max(a,b) ((a)<(b)?(b):(a))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define midd register int mid=(l+r)>>1
    #define TMP template < class ccf >
    
    TMP inline ccf qr(ccf b){
        char c=getchar();
        int q=1;
        ccf x=0;
        while(c<48||c>57)
    	q=c==45?-1:q,c=getchar();
        while(c>=48&&c<=57)
    	x=x*10+c-48,c=getchar();
        return q==-1?-x:x;
    }
    const int maxn=1e4+15;
    int n,m;
    struct E{
        int to,w,nx;
    }e[maxn<<1];
    int head[maxn];
    int cnt;
    inline void add(int fr,int to,int w,bool f){
        e[++cnt]=(E){to,w,head[fr]};
        head[fr]=cnt;
        if(f)
    	add(to,fr,w,0);
    }
    bool usd[maxn];
    int siz[maxn];
    int spa[maxn];
    int sav[maxn];
    int d[maxn];
    int rt;
    int k[105];
    bool ans[10000005];
    bool tell[105];
    int q[maxn];
    int sum;
    
    
    void dfsroot(int now,int last){
        siz[now]=1;
        spa[now]=0;
        ERP(t,now){
    	if(e[t].to!=last&&!usd[e[t].to]){
    	    dfsroot(e[t].to,now);
    	    siz[now]+=siz[e[t].to];
    	    spa[now]=Max(spa[now],siz[e[t].to]);
    	}
        }
        spa[now]=Max(spa[now],sum-siz[now]);
        if(spa[now]<spa[rt]||rt==0)
    	rt=now;
    }
    
    
    void dfsdis(int now,int last,int ew){
        d[now]=d[last]+ew;
        sav[++sav[0]]=d[now];
        ERP(t,now){
    	if(e[t].to!=last&&!usd[e[t].to]){
    	    dfsdis(e[t].to,now,e[t].w);
    	}
        }
    }
    
    inline void calc(int now){
        register int p=0;
        ERP(t,now){
    	if(!usd[e[t].to]){
    	    sav[0]=0;d[now]=0;
    	    dfsdis(e[t].to,now,e[t].w);
    	    RP(j,1,m){
    		if(!tell[j]){
    		    RP(i,1,sav[0]){
    			if(k[j]>=sav[i]){
    			    if(ans[k[j]-sav[i]])
    				tell[j]=1;
    			}
    		    }
    		}
    	    }
    	    RP(i,1,sav[0])
    		ans[sav[i]]=1;
    	    RP(i,1,sav[0])
    		q[++p]=sav[i];
    	}
        }
        
        RP(t,1,p)
    	ans[q[t]]=0;
    }
    
    void solve(int now){
        usd[now]=ans[0]=1;
        calc(now);
        ERP(t,now){
    	if(!usd[e[t].to]){
    	    sum=siz[e[t].to];
    	    rt=0;
    	    dfsroot(e[t].to,0);
    	    solve(rt);
    	}
        }
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
        freopen("out.out","w",stdout);
    #endif
        
        n=qr(1);
        m=qr(1);
        for(register int t=1,t1,t2,t3;t<n;++t){
    	t1=qr(1);
    	t2=qr(1);
    	t3=qr(1);
    	add(t1,t2,t3,1);
        }
        RP(t,1,m)
    	k[t]=qr(1),tell[t]=!k?1:0;
        sum=n;
        dfsroot(1,0);
        solve(rt);
        
        RP(t,1,m)
    	if(tell[t])
    	    puts("AYE");
    	else
    	    puts("NAY");
        return 0;
        
    }
    
    
  • 相关阅读:
    Golang的类型转换实战案例
    Golang的基础数据类型-布尔型
    Golang的运算符优先级实操案例
    Golang的单目(一元)运算符-地址操作符和接收操作符
    基于Ambari的WebUI部署kafka服务
    HBase集群优化篇
    HBase Master的高可用实战案例
    HBase 数据迁移实战案例
    HBase API实战案例
    MySQL数据源接入DBus
  • 原文地址:https://www.cnblogs.com/winlere/p/10356368.html
Copyright © 2020-2023  润新知