luogu P3258 松鼠的新家 解题报告

题目描述

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。

松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。

维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。

因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

输入格式

第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an

接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

输出格式

一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。

输入输出样例

输入:
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输出:
1
2
1
2
1

说明/提示

2<= n <=300000

题解

树链剖分模板题
很显然在a[i]->a[i+1]这条路径上直接+1,同时a[i+1]这个点-1
该查询查询 完事

代码

#include <cstdio>
#define ll long long
#define ls(x) x<<1
#define rs(x) x<<1|1
using namespace std;
inline int read(){
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') { if (c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar();}
    return x * f;
}
const int maxn=1e6+10;
struct edge{
    int next,to;
}e[2*maxn];
struct Node{
    int l,r,v,lz;
}t[4*maxn];
int head[maxn],n,m,w[maxn],a[maxn];
int d[maxn],f[maxn],sz[maxn],son[maxn];
int top[maxn],id[maxn],cnt,tot;
inline void swap(int &a,int &b) {int t=a;a=b;b=t;}
inline void add(int x,int y){
    e[++cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt;
}
inline void pushup(int x) {t[x].v=t[ls(x)].v+t[rs(x)].v;}
inline void build(int i,int l,int r){
    t[i].l=l,t[i].r=r;
    if (l==r){
        t[i].v=0;
        return;
    }
    int m=(l+r)>>1;
    build(ls(i),l,m);
    build(rs(i),m+1,r);
    pushup(i);
}
inline void pushdown(int k){
    t[ls(k)].v=t[ls(k)].v+t[k].lz*(t[ls(k)].r-t[ls(k)].l+1);
    t[rs(k)].v=t[rs(k)].v+t[k].lz*(t[rs(k)].r-t[rs(k)].l+1);
    t[ls(k)].lz=t[ls(k)].lz+t[k].lz,t[rs(k)].lz=t[rs(k)].lz+t[k].lz;
    t[k].lz=0;
}
inline void update(int k,int l,int r,int c){
    if (t[k].l>r||t[k].r<l) return;
    if (l<=t[k].l&&t[k].r<=r){
        t[k].v=t[k].v+(t[k].r-t[k].l+1)*c;
        t[k].lz=t[k].lz+c;
        return;
    }
    if (t[k].lz) pushdown(k);
    update(ls(k),l,r,c);
    update(rs(k),l,r,c);
    pushup(k);
}
inline ll query(int k,int l,int r){
    if (t[k].l>r||t[k].r<l) return 0;
    if (l<=t[k].l&&t[k].r<=r) return t[k].v;
    if (t[k].lz) pushdown(k);
    ll sum=0;
    sum=sum+query(ls(k),l,r);
    sum=sum+query(rs(k),l,r);
    return sum;
}
inline void dfs1(int u,int fa,int depth){
    f[u]=fa;
    d[u]=depth;
    sz[u]=1;
    for (int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if (v==fa) continue;
        dfs1(v,u,depth+1);
        sz[u]+=sz[v];
        if (sz[v]>sz[son[u]]) son[u]=v;
    }
}
inline void dfs2(int u,int t){
    top[u]=t;
    id[u]=++tot;
    if (!son[u]) return;
    dfs2(son[u],t);
    for (int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if (v!=son[u]&&v!=f[u]) dfs2(v,v);
    }
}
inline ll query_path(int x,int y){
    ll ans=0;
    while (top[x]!=top[y]){
        if (d[top[x]]<d[top[y]]) swap(x,y);
        ans+=query(1,id[top[x]],id[x]);
        x=f[top[x]];
    }
    if (id[x]>id[y]) swap(x,y);
    ans+=query(1,id[x],id[y]);
    return ans;
}
inline void update_path(int x,int y,int k){
    while (top[x]!=top[y]){
        if (d[top[x]]<d[top[y]]) swap(x,y);
        update(1,id[top[x]],id[x],k);
        x=f[top[x]];
    }
    if (id[x]>id[y]) swap(x,y);
    update(1,id[x],id[y],k);
}
void work(){
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<n;i++) {int a=read(),b=read();add(a,b),add(b,a);}
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    for (int i=1;i<n;++i){
        update_path(a[i],a[i+1],1);
        update_path(a[i+1],a[i+1],-1);
    }
    for (int i=1;i<=n;++i) printf("%d\n",query(1,id[i],id[i]));
}
int main(){
    work();
    return 0; 
}

转载于:https://www.cnblogs.com/cancers/p/11316229.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值