Los P3806 valley dotted governance solution to a problem

Topic link: https: //www.luogu.org/problem/P3806

Title Description

Given a tree with n dots
query tree distance is whether the presence of point k.

Input Format

n, m next n-1 edges a, b, c describe a to b to c has a path length of
the next m lines each K asks a
range of data: data for 100% of n <= 10000, m < = 100, c <= 10000, K <= 10000000

Output Format

For each line of output for each K an answer, there is output "AYE", otherwise output "NAY" (without the quotes)

answer

  Although it is a point of partition template title, but also increased the difficulty, multiple sets of inquiry, offline processing means, each partition when the judge again for each answer separately, each layer of complexity is O (n * m), reached 1e6, though, that log (n) layers, so also the complexity of the final 1e7 is.

Variable declaration:

  1. temp array: all records from the current sub-tree points to the center of gravity
  2. Array judge: temp array corresponds to a discrete, recorded from a point to the center of gravity of the presence of how many
  3. test data: the offline processing k groups ask
      how to determine whether there is a certain length in the tree? In the current partition layer, a Hypothesis length exists on the scanning temp, temp is known [I] is present, only query a-temp [i] to the presence or absence, Judge directly determined. Because there is a point in case of the same sub-tree, so even with the removal of these lengths.
      There is provided a distance to the center of gravity a, b, c for the required length of point exists and a + b = c, two situations:
    1, when a = b, for the present point i = 1 j in d g e [ a ] \sum_{i=1}^{judge[a]} I
    2, when a! = b, the point is present judge [a] * judge [b ] ( multiplication principle).
      Note judge [i] once can not be used again, it is necessary to judge [a] and judge [b] is set to zero, to avoid double counting. Finally, if this is the first time into the layer, test [i] + = answer above, if the answer is negative, when entering the test [i] - = answer above. Finally, test will be saved, and there is the possibility of each path of several possible options for how many points.

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false)
const int N = 20020, INF = 0x7f7f7f7f;

int n,m,head[N*2],num,tot,ans;//tot记录当前子树点数
int dis[N],flag[N],temp[N];
//dis记录子树每一点到根节点的距离,flag用于删除根节点,temp总汇到根节点的距离
int query[105];
int test[105];//当前路径有几条

int size[N],Max[N],root;
struct edge
{
    int next,to,len;
} G[N*2];
void add(int from,int to,int len)
{
    G[++num].next=head[from];
    G[num].to=to;
    G[num].len=len;
    head[from]=num;
}

inline void input(void)
{
    for (int i=1; i<n; i++)
    {
        int x,y,v;
        cin>>x>>y>>v;
        add(x,y,v), add(y,x,v);
    }
}

inline void dp(int fa,int cur)//求树的重心
{
    size[cur] = 1, Max[cur] = 0;
    for (int i=head[cur]; i; i=G[i].next)
    {
        int v = G[i].to;
        if ( flag[v] || v == fa ) continue;
        dp(cur,v);
        size[cur] += size[v];
        Max[cur] = max( Max[cur], size[v] );
    }
    Max[cur] = max( Max[cur], tot - size[cur] );
    if ( Max[root] > Max[cur] ) root = cur;
}

inline void dfs(int fa,int cur)
{
    temp[ ++temp[0] ] = dis[cur];
    for (int i=head[cur]; i; i=G[i].next)
    {
        int v = G[i].to;
        if ( v == fa || flag[v] ) continue;
        dis[v] = dis[cur] + G[i].len;
        dfs(cur,v);
    }
}

const int inf=10000007;
int judge[inf];
void calc(int x,int len,bool f2)
{
    dis[x] = len;
    temp[0] = 0;//temp[0]记录temp数组的长度
    dfs(0,x);

    for(int i=0; i<m; i++)
    {
        for(int j=1; j<=temp[0]; j++)
        if(temp[j]<inf)
            judge[temp[j]]++;

        int len=query[i];
        for(int j=1; j<=temp[0]; j++)
        {
            int len2=len-temp[j];
            if(len2<0)continue;

            if(judge[len2])
            {
                if(f2)
                {
                    if(len2!=temp[j])
                        test[i]+=judge[len2]*judge[temp[j]];
                    else
                        test[i]+=judge[len2]*(judge[len2]-1)/2;
                }
                else
                {
                    if(len2!=temp[j])
                        test[i]-=judge[len2]*judge[temp[j]];
                    else
                        test[i]-=judge[len2]*(judge[len2]-1)/2;
                }
                judge[len2]=0;
                judge[temp[j]]=0;
            }
        }

        for(int j=1;j<=temp[0];j++)
            if(temp[j]<inf)
                judge[temp[j]]=0;
    }
}

inline void divide(int x)
{
    flag[x] = true;//删去根节点
    calc(x,0,true);
    //cout<<"ans="<<ans<<"\n";
    for (int i=head[x]; i; i=G[i].next)
    {
        int y = G[i].to;
        if ( flag[y] ) continue;
        calc(y,G[i].len,false);//点对在同一子树的情况
        tot = size[y], root = 0;
        dp(0,y);
        divide(root);
    }
}

inline void reset(void)
{
    num = 0;
    memset( head, 0, sizeof head );
    memset( flag, 0, sizeof flag );
    ans = 0, tot = n;
    root = 0, Max[0] = INF;
}

int main(void)
{
    IOS;
    cin>>n>>m;
    reset();
    input();
    for(int i=0; i<m; i++)
        cin>>query[i];
    dp(0,1);
    divide(root);
    for(int i=0; i<m; i++)
        if(test[i])
            cout<<"AYE\n";
        else cout<<"NAY\n";
    return 0;
}
Published 41 original articles · won praise 2 · Views 1234

Guess you like

Origin blog.csdn.net/qq_41418281/article/details/101977526