[JLOI2014]松鼠的新家

[JLOI2014]松鼠的新家

题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

输出格式:

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

输入输出样例

输入样例#1: 
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输出样例#1: 
1
2
1
2
1

说明

2<= n <=300000

Soulution

树链剖分裸题。

每次对于一条链上的数加1,注意起点不用放糖,最后终点要减1.

似乎常数很大

#include<bits/stdc++.h>

using namespace std;

#define MAXN 300010

inline int read()
{
    int f=1,x=0;
    char ch;
    do
    {
        ch=getchar();
        if(ch=='-') f=-1;
    }while(ch<'0'||ch>'9');
    do
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }while(ch>='0'&&ch<='9');
    return f*x;
}

struct node
{
    int to;
    int next;
};

int n;
int a[MAXN];
int head[MAXN],cnt=0;
node g[MAXN*2];
int num[MAXN],top[MAXN],son[MAXN],fa[MAXN],dep[MAXN];
int tot[MAXN],h=0;
int add[MAXN<<2];

inline void addedge(int a,int b)
{
    ++cnt;g[cnt].to=b;g[cnt].next=head[a];head[a]=cnt;return;
}

inline void dfs1(int x,int f)
{
    son[x]=0;tot[x]=1;
    for(int i=head[x];i;i=g[i].next)
    {
        int v=g[i].to;
        if(v!=f)
        {
            fa[v]=x;
            dep[v]=dep[x]+1;
            dfs1(v,x);
            tot[x]+=tot[v];
            if(tot[son[x]]<tot[v]) son[x]=v;
        }
    }
}

inline void dfs2(int x,int now)
{
    top[x]=now;num[x]=++h;
    if(son[x]) dfs2(son[x],now);
    for(int i=head[x];i>0;i=g[i].next)
    {
        int v=g[i].to;
        if(v!=son[x]&&v!=fa[x])
        {
            dfs2(v,v);
        }
    }
}

struct s_tree
{
    int l;
    int r;
    int sum;
    inline int mid()
    {
        return (l+r)>>1;    
    } 
}tree[MAXN<<2]; 

#define lc o<<1
#define rc o<<1|1 

inline void build(int o,int l,int r)
{
    tree[o].l=l;tree[o].r=r;tree[o].sum=0;
    if(l==r) return;
    else 
    {
        int mid=tree[o].mid();
        build(lc,l,mid);
        build(rc,mid+1,r);
    }
}

inline void pushdown(int o)
{
    if(!add[o]) return;
    tree[lc].sum+=(tree[lc].r-tree[lc].l+1)*add[o];
    tree[rc].sum+=(tree[rc].r-tree[rc].l+1)*add[o];
    add[lc]+=add[o];
    add[rc]+=add[o];
    add[o]=0;
    return;
}

inline void update(int o,int x,int y,int z)
{
    int l=tree[o].l,r=tree[o].r;
    if(x<=l&&y>=r)
    {
        tree[o].sum+=(r-l+1)*z;
        add[o]+=z; 
    }
    else
    {
        if(x>r||y<l) return;
        else
        {
            int mid=tree[o].mid();
            if(add[o]) pushdown(o);
            update(lc,x,y,z);
            update(rc,x,y,z);
        }
            
    }    
} 

inline int query(int o,int x)
{
    int l=tree[o].l,r=tree[o].r;
    if(l==r) return tree[o].sum;
    else
    {
        if(add[o]) pushdown(o);
        int mid=tree[o].mid();
        if(mid>=x) return query(lc,x); 
        else return query(rc,x);
    }
}

inline void change(int a,int b)
{
    int ta=top[a],tb=top[b];
    while(ta!=tb)
    {
        if(dep[ta]<dep[tb]) swap(ta,tb),swap(a,b);
        update(1,num[ta],num[a],1);
        a=fa[ta];ta=top[a];
    }
    if(a==b) update(1,num[a],num[b],1);
    else
    {
        if(dep[a]<dep[b]) swap(a,b);
        update(1,num[b],num[a],1);
    }
}

int main()
{
    n=read();
    for(int i=1;i<=n;i++)    a[i]=read(),head[i]=-1;
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y);
        addedge(y,x);
    }
    fa[1]=0;dep[1]=1;
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,h);
    update(1,num[a[1]],num[a[1]],1);    

    for(int i=2;i<=n;i++)
    {
        change(a[i-1],a[i]);
        update(1,num[a[i-1]],num[a[i-1]],-1);
    //    cout<<query(1,num[a[1]])<<endl;
    }
    update(1,num[a[n]],num[a[n]],-1);
    for(int i=1;i<=n;i++)
    {
        printf("%d
",query(1,num[i]));
    }
}
原文地址:https://www.cnblogs.com/wlzs1432/p/9370844.html