BZOJ 3631 松鼠的新家

链剖。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxv 300500
#define maxe 600500
using namespace std;
int n,a[maxv],x,y,nume=0,g[maxv];
int w[maxv],fath[maxv],dis[maxv],son[maxv],size[maxv],top[maxv],tot=0;
int ls[maxv<<2],rs[maxv<<2],lazy[maxv<<2],root,cnt=0,ans[maxv];
struct edge
{
    int v,nxt;
}e[maxe];
void addedge(int u,int v)
{
    e[++nume].v=v;
    e[nume].nxt=g[u];
    g[u]=nume;
}
void dfs1(int x)
{
    size[x]=1;son[x]=0;
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (v!=fath[x])
        {
            fath[v]=x;
            dis[v]=dis[x]+1;
            dfs1(v);
            size[x]+=size[v];
            if (size[v]>size[son[x]])
                son[x]=v;
        }
    }
}
void dfs2(int x,int father)
{
    top[x]=father;w[x]=++tot;
    if (son[x]) dfs2(son[x],father);
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if ((v!=fath[x]) && (v!=son[x]))
            dfs2(v,v);
    }
}
void build(int &now,int left,int right)
{
    now=++cnt;lazy[now]=0;
    if (left==right) return;
    int mid=(left+right)>>1;
    build(ls[now],left,mid);
    build(rs[now],mid+1,right);
}
void modify(int now,int left,int right,int l,int r)
{
    if ((left==l) && (right==r))
    {
        lazy[now]++;
        return;
    }
    int mid=(left+right)>>1;
    if (r<=mid) modify(ls[now],left,mid,l,r);
    else if (l>=mid+1) modify(rs[now],mid+1,right,l,r);
    else
    {
        modify(ls[now],left,mid,l,mid);
        modify(rs[now],mid+1,right,mid+1,r);
    }
}
void work(int x)
{
    int p,q,f1,f2;
    p=a[x];q=a[x+1];
    f1=top[p];f2=top[q];
    while (f1!=f2)
    {
        if (dis[f1]<dis[f2])
        {
            swap(p,q);
            swap(f1,f2);
        }
        modify(root,1,n,w[f1],w[p]);
        p=fath[f1];f1=top[p];
    }
    if (dis[p]>dis[q]) swap(p,q);
    modify(root,1,n,w[p],w[q]);
}
int ask(int now,int left,int right,int p)
{
    if ((left==right) && (left==p))
        return lazy[now];
    int mid=(left+right)>>1;
    if (p<=mid) return ask(ls[now],left,mid,p)+lazy[now];
    else return ask(rs[now],mid+1,right,p)+lazy[now];
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (int i=1;i<=n-1;i++)
    {
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    dfs1(1);
    dfs2(1,1);
    build(root,1,n);
    for (int i=1;i<=n-1;i++)
        work(i);
    for (int i=1;i<=n;i++)
    {
        int now=ask(root,1,n,w[a[i]]);
        if (i!=1) now--;
        ans[a[i]]=now;
    }
    for (int i=1;i<=n;i++)
        printf("%d\n",ans[i]);
    return 0;
}
时间: 2024-10-14 07:51:57

BZOJ 3631 松鼠的新家的相关文章

【BZOJ 3631】 [JLOI2014]松鼠的新家

3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 681 Solved: 329 [Submit][Status][Discuss] Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在"树"上.松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的

BZOJ 3631: [JLOI2014]松鼠的新家( 树链剖分 )

裸树链剖分... ------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; const int maxn = 300009; struct edge { int to; edge* next; } E[maxn << 1], *pit = E, *head[maxn]; inline void add(int u,

BZOJ3631 松鼠的新家(树链剖分)

题目链接 松鼠的新家 差不多可以说是树链剖分的模板题了,直接维护即可. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i,n) for(int i(0); i < (n); ++i) 6 #define rep(i,a,b) for(int i(a); i <= (b); ++i) 7 #define dec(i,a,b) for(int i(a); i >= (b); --i) 8 #

[填坑]树上差分 例题:[JLOI2014]松鼠的新家(LCA)

今天算是把LCA这个坑填上了一点点,又复习(其实是预习)了一下树上差分.其实普通的差分我还是会的,树上的嘛,也是懂原理的就是没怎么打过. 我们先来把树上差分能做到的看一下: 1.找所有路径公共覆盖的边 例题:[NOIP2015]运输计划 (然而我还没过就先不讲了) 反正就是中间有一步要求一条边被所有计划公共覆盖. 那么怎么求它呢?暴力(滚粗).我们有一个非常好的方法就是树上差分(记录tmp为差分数组) 询问操作为从叶子节点的权值向上累加到root 在一条路径u→ v,如果tmp[u]++,那么我

P3258 松鼠的新家

松鼠的新家 洛谷链接 尽管标签是省选/NOI-,但提交的通过率已经高到三分之一了. 但它仍旧是一个省选/NOI-的题. 大致题意就是按输入的顺序走一棵树,看每个节点经过多少次.问题就相当于把一条链上的所有节点权值都加一,最后统计每个点的权值. 但这样的时间复杂度比较高,所以我们可以把这条链的头节点和尾节点的权值都加一,然后把它们的LCA减一,它们LCA的父亲节点减一.之后每次通记每个节点都统计该节点及其子树的权值和,就是这个节点被经过的次数. 而题目要求在最后的终点不需要计算,所以我们可以把"这

P3258 [JLOI2014]松鼠的新家

P3258 [JLOI2014]松鼠的新家倍增lca+树上差分,从叶子节点向根节点求前缀和,dfs求子树和即可,最后,把每次的起点和终点都. 1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<algorithm> 5 #include<cmath> 6 #include<ctime> 7 #include<set> 8 #include

【洛谷】【lca+树上差分】P3258 [JLOI2014]松鼠的新家

[题目描述:] 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n(2 ≤ n ≤ 300000)个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家.可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞.可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃. 维尼是个馋家伙,立马就

[Luogu] P3258 [JLOI2014]松鼠的新家

题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家.可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞.可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃. 维尼是个馋家伙,立马就答应了.现在松鼠希望知道为了保证维尼有

【bzoj3631】【JLOI2014】松鼠的新家

题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在"树"上.松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,--,最后到an,去参观新家. 可是这样会导致维尼重复走很多房间,懒惰的维尼不听地推辞.可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃.维尼是个馋家伙,立马就答应了. 现在松鼠希望知道为了保证维尼