1. 程式人生 > >洛谷P3806 點分治1

洛谷P3806 點分治1

點分治1

如果給你一個查詢 那就是裸的點分治 但是給你m個查詢 你該咋辦呢

不妨在查詢之前先處理好所有可能出現的邊 然後線上查詢就行

總根進行++操作 消除子樹的影響 進行--操作

具體可以看程式碼吧

/*
luogu 3806
*/
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <iostream>
#include <stack>
#include <set>
#include <map>
#include <sstream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX_N = 100024;
int f[MAX_N],siz[MAX_N];
struct edge{
    int next,v,dis;
}e[MAX_N<<1];
int eid,p[MAX_N],use[MAX_N],Siz,rt,cnt,k,ask[MAX_N],ANS[MAX_N],m,sum[MAX_N];
int d[10000005];
inline int read()
{
    int date = 0,m = 1;
    char ch = 0;
    while(ch!='-'&&(ch<'0'||ch>'9'))
        ch = getchar();
    if(ch=='-')
    {
        m = -1;
        ch = getchar();
    }
    while(ch>='0' && ch<='9')
    {
        date = date*10+ch-'0';
        ch = getchar();
    }
    return date*m;
}
inline void write(ll qw)
{
    if(qw<0)
    {
        putchar('-');
        qw = -qw;
    }
    if(qw>9)
        write(qw/10);
    putchar(qw%10+'0');
}
void init(){
    memset(p,-1,sizeof(p));
    memset(use,0,sizeof(use));
    rt = 0;
    eid = 0;
}
void Insert(int u,int v,int dis){
    e[eid].v = v;
    e[eid].dis = dis;
    e[eid].next = p[u];
    p[u] = eid++;
}
void get_rt(int u,int fa){//u為當前點,fa為父親節點
    f[u] = 0, siz[u] = 1;//f表示這個點最大子樹的大小,siz是這個點子樹大小的和
    for(int i = p[u];i!=-1;i = e[i].next){//列舉兒子
        int y = e[i].v;
        if(use[y]||y==fa) continue;//use表示之前遍歷過了,這裡沒啥用
        get_rt(y,u);//往下遍歷
        f[u] = max(f[u],siz[y]);//更新f
        siz[u] += siz[y];
    }
    f[u] = max(f[u],Siz - siz[u]);//Siz表示在現在這棵子樹中點的總數,開始時Siz=n,除了列舉的兒子所在的子樹外,還有一棵子樹是上面的那一堆,容斥原理
    if(f[u]<f[rt]) rt = u;//更新root
}

void query(int u,int fa,int dis){
    d[++cnt]=dis;
    for(int i = p[u];i!=-1;i=e[i].next){
        int y = e[i].v;
        if(use[y]||y==fa) continue;
        query(y,u,dis+e[i].dis);
    }
    return ;
}
void solve(int u,int dis,int flag){
    cnt = 0;
    query(u,0,dis);
    if(flag==1){
        for(int i = 1;i<cnt;++i)
            for(int j = i+1;j<=cnt;j++){
                sum[d[i]+d[j]]++;
            }
    }
    else {
        for(int i = 1;i<cnt;++i)
            for(int j = i+1;j<=cnt;j++)
                sum[d[i]+d[j]]--;
    }
    return;
}
void dfs(int u){//Divide
    use[u] = 1,solve(u,0,1);
    for(int i = p[u];i!=-1;i=e[i].next){
        int y = e[i].v;
        if(use[y]) continue;
        solve(y,e[i].dis,0);
        Siz = siz[y],rt = 0;
        get_rt(y,u),dfs(rt);
    }
    return ;
}
int main(){
    int n;
    n = read(),m = read();
    init();
    for(int i = 1;i<n;++i){
        int a,b,dis;
        a = read(),b = read(),dis = read();
        Insert(a,b,dis);
        Insert(b,a,dis);
    }
    f[0] = Siz = n;
    get_rt(1,0);
    dfs(rt);
    int opt;
    for(int i = 1;i<=m;++i){
        opt = read();
        if(sum[opt]) printf("AYE\n");
        else printf("NAY\n");
    }
    return 0;
}