码迷,mamicode.com
首页 > 其他好文 > 详细

【Luogu】P3806点分治模板(点分治)

时间:2018-02-05 23:13:14      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:turn   lib   read   efi   namespace   val   ret   +=   pre   

  题目链接

  wc听不懂lca讲的高等数学专场(一个字都听不懂),然后就自学了点分治。

  点分治就是我先处理完跟根有关的东西,然后把根标记掉,把原树拆成若干个联通块,然后分别对每个联通块(每个小树)搞一模一样的操作。

  然后要每次求重心,因为点分治复杂度跟递归深度有关。

  本题判断的时候偷懒用map,其实自己写的splay也快不到哪里去的样子。qwq。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<cstdlib>
#include<map>
#define maxn 200020
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch==-)    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-0;
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int next,to,val;
}edge[maxn*3];
int head[maxn],num;
inline void add(int from,int to,int val){
    edge[++num]=(Edge){head[from],to,val};
    head[from]=num;
}

map<int,bool>ext;

bool tag[maxn];
int size[maxn];
int mxn[maxn];
int stack[maxn],top;
int d[maxn];
int w[maxn];
int root=0;

void getroot(int x,int fa,int lim){
    int ret=0;size[x]=1;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa||tag[to])    continue;
        getroot(to,x,lim);
        size[x]+=size[to];
        if(ret<size[to])    ret=size[to];
    }
    if(ret<lim-size[x])    ret=lim-size[x];
    mxn[x]=ret;
    if(ret<mxn[root]||root==0)    root=x;
}

void depfind(int x,int fa,int dst){
    stack[++top]=dst;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa||tag[to])    continue;
        depfind(to,x,dst+edge[i].val);
    }
    return;
}

int getsize(int x,int fa){
    int ans=1;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa||tag[to])    continue;
        ans+=getsize(to,x);
    }
    return ans;
}

void dfs(int x,int lim,int m){
    root=0;
    getroot(x,x,lim);
    tag[root]=1;
    ext.clear();ext[0]=1;
    for(int i=head[root];i;i=edge[i].next){
        int to=edge[i].to;
        if(tag[to])    continue;
        top=0;
        depfind(to,to,edge[i].val);
        sort(stack+1,stack+top+1);
        for(int j=1;j<=m;++j){
            if(w[j])    continue;
            for(int k=1;k<=top;++k){
                int now=d[j]-stack[k];
                if(ext[now]==1)    w[j]=1;
            }
        }
        for(int j=1;j<=top;++j)    ext[stack[j]]=1;
    }
    int now=root;
    for(int i=head[now];i;i=edge[i].next){
        int to=edge[i].to;
        if(tag[to])    continue;
        int ret=getsize(to,to);
        dfs(to,ret,m);
    }
}

int main(){
    int n=read(),m=read();
    for(int i=1;i<n;++i){
        int x=read(),y=read(),z=read();
        add(x,y,z);
        add(y,x,z);
    }
    for(int i=1;i<=m;++i)    d[i]=read();
    dfs(1,n,m);
    for(int i=1;i<=m;++i)
        if(w[i]==1)    printf("AYE\n");
        else        printf("NAY\n");
    return 0;
}
/*
13 10
1 2 1
1 4 2
4 3 5
4 5 11
5 6 4
5 7 2
4 8 7
1 10 2
9 10 9
1 11 4
11 13 5
11 12 6
12
11
10
9
8
22
13
14
15
18
*/

 

【Luogu】P3806点分治模板(点分治)

标签:turn   lib   read   efi   namespace   val   ret   +=   pre   

原文地址:https://www.cnblogs.com/cellular-automaton/p/8419515.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!