Tree upgrade training exercises

Tags (separated by spaces): 517coding solution problem


Task 1

On the edge of the trees were differential.

Considering the path \ (u - v \) may be $ c_u + = 1, c_v + = 1, c_ {lca (u, v)} - = 2 $

Praying tree and then answers, for each point and sub-tree, is this point that edge up to a whole tree.

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

# include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct rec{ int pre,to; }a[N<<1];
int head[N],tot=1,ans[N],c[N],dep[N],g[N][22],n,m;
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1; g[u][0]=fa;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs(v,u);
    }
}
void init()
{
    dfs(1,0);
    for (int i=1;i<=21;i++)
     for (int j=1;j<=n;j++)
      g[j][i]=g[g[j][i-1]][i-1];
}
int lca(int u,int v)
{
    if (dep[u]<dep[v]) swap(u,v);
    for (int i=21;i>=0;i--)
     if (dep[g[u][i]]>=dep[v]) u=g[u][i];
    if (u==v) return u;
    for (int i=21;i>=0;i--)
     if (g[u][i]!=g[v][i]) u=g[u][i],v=g[v][i];
    return g[u][0];
}
void dfs2(int u,int fa,int to)
{
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs2(v,u,i>>1);c[u]+=c[v];
    }
    ans[to]=c[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);
    }
    scanf("%d",&m);
    init();
    for (int i=1;i<=m;i++) {
        int u,v;scanf("%d%d",&u,&v);
        c[u]++; c[v]++; c[lca(u,v)]-=2;
    }
    dfs2(1,0,0);
    for (int i=1;i<=n-1;i++) printf("%d ",ans[i]);
    return 0;
}

Task 2

The first topic is connected to the black and white dots are shrunk to a point.

Then the tree became a point of black and white.

So if the point is bound to be changed from the center outward radiation for a certain operating point, this point can be constantly centered communication block dyed the same color.

for example, 1 0 1 0 1 for the first time into 10,001 second may become 11,111.

So for a tree, the optimal operating point is obviously the midpoint of the diameter of the tree.

All issues will be transformed into stained diameter such that the diameter of the tree becomes the same color.

If the length is odd considered: the form 101, the answer is len / 2
if the length is an even number: the form 10, the answer is len / 2

Complexity is \ (O (n) \)

# 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,m,tot,d[N],belong[N];
vector<int>E[N];
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs1(int u,int num)
{
    belong[u]=num;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to;
        if ((belong[v]==-1) && (w[v]==0)) dfs1(v,num);
    }
}
void dfs2(int u,int num)
{
    belong[u]=num;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to;
        if ((belong[v]==-1) && (w[v]==1)) dfs2(v,num);
    }
}
void dfs3(int u,int fa,int L)
{
    d[u]=L;
    for (int i=0;i<E[u].size();i++)
     if (E[u][i]!=fa) dfs3(E[u][i],u,L+1);
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&w[i]);
    for (int i=1;i<n;i++) {
        int u,v; scanf("%d%d",&u,&v);
        adde(u,v); adde(v,u);
    }
    memset(belong,-1,sizeof(belong)); int tt=0;
    for (int i=1;i<=n;i++) if ((belong[i]==-1) && (w[i]==0)) tt++,dfs1(i,tt);
    for (int i=1;i<=n;i++) if ((belong[i]==-1) && (w[i]==1)) tt++,dfs2(i,tt);
    
    for (int u=1;u<=n;u++) for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to;
        if (belong[v]!=belong[u]) E[belong[v]].push_back(belong[u]);
    }
    for (int i=1;i<=tt;i++){
        int tmp=unique(E[i].begin(),E[i].end())-E[i].begin();
        E[i].erase(E[i].begin()+tmp,E[i].end());
    }
    memset(d,0,sizeof(d)); int pt=0;
    dfs3(1,0,1);
    for (int i=1;i<=tt;i++) if (d[pt]<d[i]) pt=i;
    memset(d,0,sizeof(d)); int ans=0;
    dfs3(pt,0,1);
    for (int i=1;i<=tt;i++) if (ans<d[i]) ans=d[i];
    printf("%d\n",ans>>1);
    return 0;
}

Task 3

The classic tree path post questions.

Consider two paths \ ([a, b], [c, d] \) conditions post.

Is \ (lca (a, b) \) in \ ([c, d] \ ) or on \ (lca (c, d) \) in \ ([a, b] \ ) on.

A better strategy is to try to select \ (lca \) large depth of the path, at least not so bad.

First of all, each path contributing the most to answer 1, and if the depth is smaller, then the more likely other paths intersect. If the depth of the case in accordance with the first increment, not worse.

When processed, if \ (u \) is $ lca $ path is legitimate, then the other nodes in its sub-tree can not be the starting point for the inevitable path, so directly to its sub-tree assignment is false.

This way complexity is right, and

Complexity $ (n log n) O $

# include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node{ int u,v,l;}p[N];
struct rec{ int pre,to;}a[N<<1];
int n,m,tot,head[N],dep[N],g[N][22];
bool vis[N];
void clear()
{
    memset(p,0,sizeof(p)); memset(a,0,sizeof(a));
    memset(head,0,sizeof(head)); memset(dep,0,sizeof(dep));
    memset(g,0,sizeof(g)); memset(vis,false,sizeof(vis));
    tot=0;
}
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1; g[u][0]=fa;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs(v,u);
    }
}
void init()
{
    dfs(1,0);
    for (int i=1;i<=21;i++)
     for (int j=1;j<=n;j++)
      g[j][i]=g[g[j][i-1]][i-1];
}
int lca(int u,int v)
{
    if (dep[u]<dep[v]) swap(u,v);
    for (int i=21;i>=0;i--)
     if (dep[g[u][i]]>=dep[v]) u=g[u][i];
    if (u==v) return u;
    for (int i=21;i>=0;i--)
     if (g[u][i]!=g[v][i]) u=g[u][i],v=g[v][i];
    return g[u][0];
}
bool cmp(node a,node b){return dep[a.l]>dep[b.l];}
void draw(int u,int fa)
{
    vis[u]=true;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa||vis[v]) continue;
        draw(v,u);
    }
}
int main ()
{
    while (~scanf("%d%d",&n,&m)) {
        clear();
        for (int i=2;i<=n;i++) {
            int u,v; scanf("%d%d",&u,&v);
            adde(u,v); adde(v,u);
        }
        init();
        for (int i=1;i<=m;i++) {
            scanf("%d%d",&p[i].u,&p[i].v);
            p[i].l=lca(p[i].u,p[i].v);
        }
        sort(p+1,p+1+m,cmp);
        int ans=0; memset(vis,false,sizeof(vis));
        for (int i=1;i<=m;i++) {
            if (vis[p[i].u]||vis[p[i].v]) continue;
            ans++; draw(p[i].l,g[p[i].l][0]);
        }
        printf("%d\n",ans);

    }
    return 0;
}

Task 4

Any tree of a first diameter to find out, consider the tree's diameter must intersect at a line on.
So a diameter of from two to the middle section of this intermediate must search path is unique.

Diameter is set \ ([S, T] \) , the diameter of the pulled out, the left side is \ (S \) , the right is \ (T \) ;

  • First to \ (S \) root, and then run a whole tree, and determine its subtree longest chain of several.
  • From \ (T \) leftward traverse the entire diameter, find a leftmost point \ (V \) such that the right adjacent one side edge is not a necessary (even if the right to obtain the maximum number of the current point of the chain do not change)
  • Then \ (T \) root, and then run a whole tree, and determine its subtree longest chain of several.
  • From \ (S \) traversing the entire diameter of the right, to find a point rightmost \ (U \) such that it is not left adjacent to one side to give a necessary, even if the left side of the maximum number of chain (current point do not change)
  • Chain \ ([u, v] \ ) in all edges are a necessary edge.

The above process clearly is a linear process, complexity is \ (O (n) \)

# include <cstdio>
# include <iostream>
# include <cstring>
# define int long long
using namespace std;
const int N=2e5+10;
struct rec{ int pre,to,w;}a[N<<1];
int n,tot;
int d[N],head[N],tim[N],f[N],path[N],pre[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 dfs1(int u,int fa,int L)
{
    d[u]=L;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs1(v,u,L+a[i].w);
    }
}
void dfs2(int u,int fa,int L)
{
    d[u]=L;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        pre[v]=u; dfs2(v,u,L+a[i].w);
    }
}
void dfs3(int u,int fa)
{
    int cnt=0,mx=0; bool leaf=1;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue; leaf=0;
        dfs3(v,u);
        if (f[v]+a[i].w>mx) mx=f[v]+a[i].w,cnt=tim[v];
        else if (f[v]+a[i].w==mx) cnt+=tim[v];
    }
    if (leaf) f[u]=0,tim[u]=1;
    else f[u]=mx,tim[u]=cnt;
}
signed main()
{
    scanf("%lld",&n);
    for (int i=1;i<n;i++) {
        int u,v,w; scanf("%lld%lld%lld",&u,&v,&w);
        adde(u,v,w); adde(v,u,w);
    }
    memset(d,0,sizeof(d));
    dfs1(1,0,0); int s=0;
    for (int i=1;i<=n;i++) if (d[i]>d[s]) s=i;
    memset(d,0,sizeof(d));
    dfs2(s,0,0); int t=0; pre[s]=-1;
    for (int i=1;i<=n;i++) if (d[i]>d[t]) t=i;
    printf("%lld\n",d[t]);
    int u=t,v; while (pre[u]!=-1) path[++path[0]]=u,u=pre[u]; path[++path[0]]=u;
    for (int i=1;i<=path[0]/2;i++) swap(path[i],path[path[0]-i+1]);
    memset(f,0,sizeof(f)); memset(tim,0,sizeof(tim)); dfs3(s,0);
    v=path[0];
    for (int i=path[0]-1;i>=1;i--)
     if (tim[path[i]]-tim[path[i+1]]>0) v=i;
    memset(f,0,sizeof(f)); memset(tim,0,sizeof(tim)); dfs3(t,0);
    u=1;
    for (int i=2;i<=path[0];i++)
     if (tim[path[i]]-tim[path[i-1]]>0) u=i;
    printf("%lld\n",v-u);
    return 0;
}

Task 5

According to the above approach to add a leaf, may increase the diameter of at most 1.

We only need to maintain the current diameter of the tree (the two endpoints) on it.

Is provided before the end \ (A, B \) of the current adding a new leaf \ (X \) ,

  • \(dist(x,A) > Now\) : $Now = dist(x,A),B=x $
  • \(dist(x,B) > Now\) : $Now = dist(x,B),A=x $

Offline processing to make trouble \ (lca \) on it.

Complexity is \ (O ((2q + 4 ) \ log \ (2q + 4)) \)

# include <bits/stdc++.h>
using namespace std;
const int N=1e6+1000;
struct rec{ int pre,to;}a[N<<1];
int head[N],q[N],n,tot,dep[N],g[N][22];
void adde(int u,int v)
{
    a[++tot].pre=head[u];
    a[tot].to=v;
    head[u]=tot;
}
void dfs(int u,int fa)
{
    g[u][0]=fa; dep[u]=dep[fa]+1;
    for (int i=head[u];i;i=a[i].pre) {
        int v=a[i].to; if (v==fa) continue;
        dfs(v,u);
    }
}
void init()
{
    dfs(1,0);
    for (int i=1;i<=21;i++)
     for (int j=1;j<=n;j++)
      g[j][i]=g[g[j][i-1]][i-1];
}
int lca(int u,int v)
{
    if (dep[u]<dep[v]) swap(u,v);
    for (int i=21;i>=0;i--)
     if (dep[g[u][i]]>=dep[v]) u=g[u][i];
    if (u==v) return u;
    for (int i=21;i>=0;i--)
     if (g[u][i]!=g[v][i]) u=g[u][i],v=g[v][i];
    return g[u][0];
}
int dist(int x,int y)
{
    int l=lca(x,y);
    return (dep[x]-dep[1]+dep[y]-dep[1])-2*(dep[l]-1);
}
int main()
{
    //freopen("1.in","r",stdin);
    int Q; scanf("%d",&Q);
    n=4; adde(1,2); adde(2,1); adde(1,3); adde(3,1); adde(1,4); adde(4,1);
    for (int i=1;i<=Q;i++) {
        scanf("%d",&q[i]);
        adde(n+1,q[i]); adde(q[i],n+1);
        adde(n+2,q[i]); adde(q[i],n+2);
        n+=2;
    }
    init();
    int now=2,A=2,B=4,m=4;
    for (int i=1;i<=Q;i++) {
        int u=q[i],v=++m;
        int d1=dist(v,A),d2=dist(v,B);
        if (d1>now) now=d1,B=v;
        else if (d2>now) now=d2,A=v;
        v=++m;
        d1=dist(v,A),d2=dist(v,B);
        if (d1>now) now=d1,B=v;
        else if (d2>now) now=d2,A=v;
        printf("%d\n",now);
    }
    return 0;
}

Task 6

The first question is the greatest spanning tree, while the right sort of run naked kruskal it.

Q satisfies the second request to the path tree \ ([u, v] \ ) two of the number \ (i, j \) points satisfying \ (i> j \) under conditions maximizing \ (c_i - c_j \) values.

Considering the number of restrictions on the answers, so we might consider doubling to complete limit.

5 may first be doubled arrays, respectively, " \ (U \) jump up \ (2 ^ j \) whose nodes are", " \ (U \) jump up \ (2 ^ j \) legal maximum "," \ (U \) jump up \ (2 ^ j \) legal minimum "," \ (U \) jump up \ (2 ^ j \) legal maximum poor (ancestor - grandson), " " \ (U \) jump up \ (2 ^ j \) legal maximum poor (grandson - the ancestors)."

Finally, the answer must be a \ ([U, LCA] \) , \ ([v, LCA] \) , cross \ (lca \) three-part piece together what you can.

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

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
#include<stack>
#define N 60000
std::queue<int>q; 
struct aa{
    int p,next;
}da[N*3];
struct noz{
    int x,y,len;
}line[N*2];
int fa[N],dd,tou[N],mx[N][21],mi[N][21],fm[N][21],dp[N][21],dp2[N][21];
int n,b[N],m,dep[N];
bool vis[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void add(int x,int y){
    da[++dd].p=y;da[dd].next=tou[x];tou[x]=dd;
    da[++dd].p=x;da[dd].next=tou[y];tou[y]=dd;
}
void bfs(){
    q.push(1);
    vis[1]=1;
    dep[1]=1;
    while (!q.empty()){
        int u=q.front();q.pop();
        for (int i=tou[u];i;i=da[i].next){
            int v=da[i].p;
            if (!vis[v]){
                dep[v]=dep[u]+1;
                q.push(v),vis[v]=1;
                fm[v][0]=u;
                mx[v][0]=std::max(b[v],b[u]);
                mi[v][0]=std::min(b[v],b[u]);
                dp[v][0]=b[u]-b[v];
                dp2[v][0]=b[v]-b[u];
            }
        }
        for (int i=1;i<=20;i++){
            fm[u][i]=fm[fm[u][i-1]][i-1];
            if (!fm[u][i])break;
            mx[u][i]=std::max(mx[u][i-1],mx[fm[u][i-1]][i-1]);
            mi[u][i]=std::min(mi[u][i-1],mi[fm[u][i-1]][i-1]);
            dp[u][i]=std::max(dp[u][i-1],mx[fm[u][i-1]][i-1]-mi[u][i-1]);
            dp[u][i]=std::max(dp[u][i],dp[fm[u][i-1]][i-1]);
            dp2[u][i]=std::max(dp2[u][i-1],mx[u][i-1]-mi[fm[u][i-1]][i-1]);
            dp2[u][i]=std::max(dp2[u][i],dp2[fm[u][i-1]][i-1]);
        }
    }
}
int lca(int x,int y){
    if (dep[x]<dep[y])std::swap(x,y);
    for (int i=20;i>=0;i--)
      if (dep[x]-dep[y]>=1<<i)x=fm[x][i];
    if (x==y)return x;
    for (int i=20;i>=0;i--)
      if (fm[x][i]!=fm[y][i]){
        x=fm[x][i];
        y=fm[y][i];
      }
    if (x==y)return x;
    else return fm[x][0];
}
int getMAX(int x,int goal){
    int ma=0;
    for (int i=20;i>=0;i--)
      if (dep[x]-dep[goal]>=1<<i){
        ma=std::max(ma,mx[x][i]);
        x=fm[x][i];
      }
    return ma;
} 
int  getMIN(int x,int goal){
    int ma=0x5f5f5f5f;
    for (int i=20;i>=0;i--)
      if (dep[x]-dep[goal]>=1<<i){
        ma=std::min(ma,mi[x][i]);
        x=fm[x][i];
      }
    return ma;
}
int opre1(int x,int goal){
    int ma=0x5f5f5f5f;
    int num=0;
    for (int i=20;i>=0;i--)
     if (dep[x]-dep[goal]>=1<<i){
        num=std::max(num,dp[x][i]);
        num=std::max(num,mx[x][i]-ma);
        ma=std::min(ma,mi[x][i]);
        x=fm[x][i];
    }
    return num;
}
int opre2(int x,int goal){
    int ma=-0x5f5f5f5f;
    int num=0;
    for (int i=20;i>=0;i--)
     if (dep[x]-dep[goal]>=1<<i){
        num=std::max(num,dp2[x][i]);
        num=std::max(num,ma-mi[x][i]);
        ma=std::max(ma,mx[x][i]);
        x=fm[x][i];
    }
    return num;
}
bool cmp(noz a,noz b){return a.len>b.len;}
int main(){
    while (scanf("%d",&n)!=EOF){
        dd=0;
        memset(tou,0,sizeof(tou));
        memset(vis,0,sizeof(vis));
        memset(dep,0,sizeof(dep));
        for (int i=1;i<=n;i++)fa[i]=i;
        for (int i=1;i<=n;i++)
          for (int j=0;j<=20;j++)
            mx[i][j]=dp[i][j]=dp2[i][j]=fm[i][j]=0,mi[i][j]=0x5f5f5f5f;
        for (int i=1;i<=n;i++)scanf("%d",&b[i]); 
        scanf("%d",&m);
        for (int i=1;i<=m;i++)scanf("%d%d%d",&line[i].x,&line[i].y,&line[i].len);
        std::sort(line+1,line+1+m,cmp);
        int tot=0;int sum=0;
        for (int i=1;i<=m;i++){
            int fx=find(line[i].x);
            int fy=find(line[i].y);
            if (fx!=fy){
                fa[fx]=fy;
                ++tot;
                sum+=line[i].len;
                add(line[i].x,line[i].y);
                if (tot==n-1)break;
            }
        }
        printf("%d\n",sum);
        bfs();
        int q;
        scanf("%d",&q);
        for (int i=1;i<=q;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            int LCA=lca(x,y);
            int x1=opre1(x,LCA);
            int x2=opre2(y,LCA);
            printf("%d\n",std::max(std::max(x1,x2),getMAX(y,LCA)-getMIN(x,LCA)));
        }
    }
    return 0;
}

Guess you like

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