Problem tree

Task 1

Defined center of gravity tree: to this point is the root, then the size of all of its sub-tree no more than half of the entire tree.

First, the focus must be leaf nodes themselves.
Consider node u heaviest son v, it is clearly the ultimate answer must jump several steps up in the center of gravity of the son (not to jump to sub-tree outside)

Due to the presence of the center of gravity, it does not only need to meet half the number of nodes and son subtree in the current does not exceed the entire subtree can.

# include <bits/stdc++.h>
using namespace std;
const int N=3e5+10;
struct rec{ int pre,to;}a[N<<1];
int head[N],fa[N],ans[N],size[N];
int n,m,tot;
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs1(int u,int f)
{
    fa[u]=f; size[u]=1;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==f) continue;
        dfs1(v,u); size[u]+=size[v];
    }
    if (size[u]==1) ans[u]=u;
}
void dfs2(int u,int f)
{
    if (size[u]==1) return;
    ans[u]=u; int ret=0;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==f) continue;
        dfs2(v,u);
        if (size[v]>size[ret]) ret=v;
    }
    if (size[u]<(size[ret]<<1)) {
        int v=ans[ret];
        while (((size[u]-size[v])<<1)>size[u]) v=fa[v];
        ans[u]=v;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=2;i<=n;i++) {
        int t; scanf("%d",&t);
        adde(i,t); adde(t,i);
    }
    dfs1(1,0);

    dfs2(1,0);
    for (int i=1;i<=m;i++) {
        int x; scanf("%d",&x);
        printf("%d\n",ans[x]);
    }
    return 0;
}

Task 2

Consider a sqrt (n) approach n.
Information about the number of recording the number of each node on the path to the root node, the prefix is updated coefficient information change point answers.
Still a little update: deletes the current point, additional do it again.

I remember back when erase information.

But this does not direct violence + pruning to the quick ...

This is a standard process of TLE

# include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
struct rec{ int pre,to;}a[N<<1];
int w[N],head[N],n,cnt,t[N],ans[N],tot;
map<int,int>mp;
vector<int>pp[N];
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs1(int u,int fa,int L)
{
    ans[u]=L;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs1(v,u,gcd(L,w[u]));
    }
}
void dfs2(int u,int fa,int dep)
{
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        for (int j=0;j<pp[v].size();j++) {
            mp[pp[v][j]]++;
            if (mp[pp[v][j]]>dep) ans[v]=max(ans[v],pp[v][j]);
        }
        dfs2(v,u,dep+1);
        for (int j=0;j<pp[v].size();j++) mp[pp[v][j]]--;
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&w[i]);
    for (int i=1;i<=n-1;i++) {
        int u,v; scanf("%d%d",&u,&v);
        adde(u,v); adde(v,u);
    }
    dfs1(1,0,0);
    for (int i=1;i<=n;i++) {
        int x=w[i];
        for (int j=1;j<=sqrt(x);j++)
        if (x%j==0) {
            pp[i].push_back(j);
            if (x/j!=j) pp[i].push_back(x/j);
        }
    }
    for (int i=0;i<pp[1].size();i++) mp[pp[1][i]]++;
    ans[1]=max(ans[1],w[1]);
    dfs2(1,0,0);
    for (int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}

Here then is a strange pruning AC program:

# include <bits/stdc++.h>
using namespace std;
const int N=3e5+10;
struct rec{
    int pre,to;
}a[N<<1];
int tot,n;
int ans[N],w[N],dis[N],head[N];
int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs(int u,int fa)
{
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        ans[v]=dis[v]=gcd(dis[u],w[v]);
        dfs(v,u);
    }
}
void work(int u,int fa,int d)
{
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        int t=gcd(d,w[v]);
        if (ans[v]%t==0) continue;
        ans[v]=max(ans[v],t); work(v,u,t);
    }
}
void dfs2(int u,int fa)
{
    ans[u]=max(ans[u],dis[fa]);
    work(u,fa,dis[fa]);
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs2(v,u);
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&w[i]);
    for (int i=2;i<=n;i++) {
        int u,v; scanf("%d%d",&u,&v);
        adde(u,v); adde(v,u);
    }
    ans[1]=dis[1]=w[1];
    dfs(1,0); dfs2(1,0);
    for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}

Task 3

Apparently Alice's optimal path is gradually pressed to Bob,
and Bob might flee to his father direction, but will select a node longest chain running along the node.

Set \ (c_ {u} \) represents the maximum chain length of node u or less (including u)

Obviously, it turned to meet its longest chain run is legitimate in the following node.

If and only if \ (dep_ {x} - dep_
{u}> dep_ {u} -dep_ {1} \) for all legal point u, we need the maximum total number of two-person operation calculated.

Noted that stop here in the original position is not fixed in one operation,
i.e. maximizes $ 2 \ times (dep_u - dep_1 + c_ {u} -1) $

# include<bits/stdc++.h>
# define int long long
using namespace std;
const int N=4e5+10;
struct rec{ int pre,to;}a[N<<1];
int n,x,head[N],tot,c[N],dep[N],f[N];
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs(int u,int fa)
{
    int mx=0;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dep[v]=dep[u]+1; f[v]=u; dfs(v,u); mx=max(mx,c[v]);
    }
    c[u]=1+mx;
}
signed main()
{
    scanf("%lld%lld",&n,&x);
    for (int i=1;i<n;i++) {
        int u,v; scanf("%lld%lld",&u,&v);
        adde(u,v); adde(v,u);
    }
    dfs(1,0);
    int y=x,ans=0;
    do {
        if (dep[x]-dep[y]<dep[y]-dep[1]) 
         ans=max(ans,2*(dep[y]-dep[1]+c[y]-1));
        y=f[y];
    }while (y!=1);
    if (dep[x]-dep[y]<dep[y]-dep[1]) ans=max(ans,2*(dep[y]-dep[1]+c[y]-1));
    printf("%lld\n",ans);
    return 0;
 }

Task 4

Consider if a node is removed, in order to make a leaf node delete, delete all must take its sub-tree, which is the size of the contribution of the answer.

In the course of the maximum dfs event of the prefix and the right side is less than 0, and then as the sub-root node from one end of the current path, i.e. the path length remains assigned to 0, which is equivalent to the current node records starting up consecutive sub-segments, and (greedy selection).

Such complexity is $ O (n) $ of

# include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct rec{ int pre,to,w;}a[N<<1];
int lim[N],n,head[N],tot,ans;
void adde(int u,int v,int w)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    a[tot].w=w;
    head[u]=tot;
}
void dfs(int u,int fa,int L)
{
    if (lim[u]<L) return;
    ans++;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs(v,u,max(L+a[i].w,0));
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&lim[i]);
    for (int i=2;i<=n;i++) {
        int u=i,v,w; scanf("%d%d",&v,&w);
        adde(u,v,w); adde(v,u,w);
    }
    dfs(1,0,0);
    printf("%d\n",n-ans);
    return 0;
}

Task 5

Very clearly, the set of points may be required, and all points are smaller than the distance of the farthest point is equal to d and at this point only the set of points which can be d or less.

For any point to the farthest point set point must be focused on two points of the two points furthest apart one.

If the farthest point is not one of the two points, it will inevitably lead to another through the farthest point and the farthest point of the path is composed of a diameter longer than the original, in contradiction to the devil dot diameter.

How to find the point marked two furthest apart.

Dfs can be used twice.

Then starting from two points to find a dfs, taking a max.

Then sweep aside all the points, and if the answer is less than equal to d then included in the answer.

Complexity \ (O (n) \)

# include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct rec{
    int pre,to;
}a[N<<1];
bool mark[N];
int n,m,lim,tot,head[N],d[N];
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs1(int u,int fa)
{
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        d[v]=d[u]+1;
        dfs1(v,u);
    }
}
void dfs2(int u,int fa,int step)
{
    d[u]=max(d[u],step);
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs2(v,u,step+1);
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&lim);
    memset(mark,false,sizeof(mark));
    for (int i=1;i<=m;i++) {
        int t; scanf("%d",&t); mark[t]=true;
    }
    for (int i=2;i<=n;i++) {
        int u,v; scanf("%d%d",&u,&v);
        adde(u,v); adde(v,u);
    }
    memset(d,0,sizeof(d)); d[0]=-1;
    dfs1(1,0); int pt1=0; 
    for (int i=1;i<=n;i++) if ((d[i]>d[pt1])&&mark[i]) pt1=i;
    memset(d,0,sizeof(d)); d[0]=-1;
    dfs1(pt1,0);int pt2=0;
    for (int i=1;i<=n;i++) if  ((d[i]>d[pt2])&&mark[i]) pt2=i;
    memset(d,0,sizeof(d)); d[0]=-1;
    dfs2(pt1,0,0);dfs2(pt2,0,0);
    int ans=0;
    for (int i=1;i<=n;i++) if (d[i]<=lim) ans++;
    printf("%d\n",ans);
    return 0;
}

Task 6

Obviously there will be two very special situation, that is,

  • n = 1, the answer is 1 (according to staining chain shape)
  • n = 2 for answers to 2 (according to staining chain shape)
  • n> 2 When the lower limit of the answer 3

Dyeing, Imperial node 1, and then start from 1 node traversal to each node when his son staining of the node (the current reference point and the current point of color father, the son is not repeated number)

# include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
struct rec{
    int pre,to;
}a[N<<1];
int head[N],tot,n,k,col[N]; 
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs(int u,int fa)
{
    int num=1;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        while (col[u]==num||col[fa]==num) num++;
        col[v]=num++;  k=max(k,col[v]);
        dfs(v,u);
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++) {
        int u,v; scanf("%d%d",&u,&v);
        adde(u,v); adde(v,u);
    }
    col[1]=1; dfs(1,0);
    printf("%d\n",k);
    for (int i=1;i<=n;i++) printf("%d ",col[i]);
    puts("");
    return  0;
}

Task 7

Take any root = 1
consider each point contribution to this point to the root of the answer.

Since the edge weight \ (w> 0 \) so prefix and monotonic, can be found multiplying a certain critical point \ (X \) just to the current point \ (U \) a distance less \ (a_v \) , then bound , \ (the X-\) to \ (father (u) \) at all points in the chain will be consistent with answers.

Consider only path to maintain a adder, ask specific values ​​for each end node.

The tree can be used to solve the differential.

Maintenance right path adder, for a \ (u, v \) chain operation, then \ (d_u + =. 1 \) , \ (D_v + =. 1 \) , \ (D_ {LCA (U, V)} - =. 1, D_ {Father (LCA (U, V))} - =. 1 \) .

And then finally ran straight sub-tree and is the original tree.

Complexity \ (O (n \ log \ n) \)

# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=2e5+10;
struct rec{
    int pre,to,w;
}a[N<<1];
int tot,n;
int head[N],c[N],g[N<<1][20],d[N<<1][20],w[N];
void adde(int u,int v,int w)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    a[tot].w=w;
    head[u]=tot;
}
void dfs(int u,int fa)
{
    g[u][0]=fa;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        d[v][0]=a[i].w; dfs(v,u);
    }
}
void init()
{
    dfs(1,0);
    for (int i=1;i<=18;i++)
     for (int j=1;j<=n;j++)
      g[j][i]=g[g[j][i-1]][i-1],
      d[j][i]=d[j][i-1]+d[g[j][i-1]][i-1];
}
int jump(int u,int sum)
{
    for (int i=18;i>=0;i--)
     if (d[u][i]<=sum&&g[u][i]!=0) { sum-=d[u][i]; u=g[u][i];}
    return u;  
}
void dfs2(int u,int fa)
{
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs2(v,u); c[u]+=c[v];
    }
}
signed main()
{
    scanf("%lld",&n);
    for (int i=1;i<=n;i++) scanf("%lld",&w[i]);
    for (int i=2;i<=n;i++) {
        int u=i,v,w; scanf("%lld%lld",&v,&w);
        adde(u,v,w); adde(v,u,w);
    }
    init();
    for (int i=1;i<=n;i++) {
        int to=jump(i,w[i]); 
        c[g[to][0]]--; c[g[i][0]]++;
    }
    dfs2(1,0);
    for (int i=1;i<=n;i++) printf("%lld ",c[i]); puts("");
    return 0;
}

Guess you like

Origin www.cnblogs.com/ljc20020730/p/11291471.html