• [JLOI2014]松鼠的新家


    洛谷3258

    题目描述

    松鼠的新家是一棵树,前几天刚刚装修了新家,新家有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

    分析:首先很容易看出是树链剖分

    本题先告诉你是一棵树,然后要这只小熊在树上走,每经过一个点都要放一颗糖果,问每个点放了几个糖果。这显然是对树上的链进行操作,这就想到了树链剖分。

    其实就是一个模板。

    但本题要注意的是每次到达一个点,要放一次糖果,但你从这个点走向下一个点的时候就不要放糖果了,所以每次再在这个点上进行减一就行了。

    传送门:洛谷3258

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define ll(x) (x*2)
    #define rr(x) (x*2+1)
    typedef long long ll;
    int lazy[600100],last[600100],w[600100],dep[600010],fa[600010],n,len=0;
    int siz[600010],son[600100],cnt=0,id[600100],wt[600100],sum[2000100];
    int top[600100],kkk[600100],yuan[600010],ansk[600010];
    struct node
    {
        int to,next;
    }a[600100];
    void add(int a1,int a2)
    {
        len++;
        a[len].to=a2;
        a[len].next=last[a1];
        last[a1]=len;
    }
    void dfs1(int x,int father,int deep)
    {
        dep[x]=deep;
        fa[x]=father;
        siz[x]=1;
        int maxson=-1;
        for(int i=last[x];i;i=a[i].next)
        {
            int to=a[i].to;
            if(to==father)
            continue;
            dfs1(to,x,deep+1);
            siz[x]+=siz[to];
            if(siz[to]>maxson) son[x]=to,maxson=siz[to];
        }
    }
    void dfs2(int x,int topf)
    {
        cnt++;
        id[x]=cnt;
        yuan[cnt]=x;
        wt[cnt]=w[x];
        top[x]=topf;
        if(!son[x]) return;
        dfs2(son[x],topf);
        for(int i=last[x];i;i=a[i].next)
        {
            int to=a[i].to;
            if(to==fa[x]||to==son[x]) continue;
            dfs2(to,to);
        }
    }
    void xia(int node,int lsum,int rsum)
    {
        if(lazy[node])
        {
            lazy[ll(node)]+=lazy[node];
            lazy[rr(node)]+=lazy[node];
            sum[ll(node)]+=lsum*lazy[node];
            sum[rr(node)]+=rsum*lazy[node];
            lazy[node]=0;
            return;
        }
    }
    void gai(int node,int left,int right,int l,int r,int k)
    {
        if(l<=left&&right<=r)
        {
            sum[node]+=(k*(right-left+1));
            lazy[node]+=k;
            return;
        }
        if(left>r||right<l) return;
        int mid=(left+right)/2;
        xia(node,mid-left+1,right-mid);
        if(left<=mid) gai(ll(node),left,mid,l,r,k);
        if(right>mid) gai(rr(node),mid+1,right,l,r,k);
        sum[node]=(sum[ll(node)]+sum[rr(node)]);
    }
    void gai1(int x,int y,int k)
    {
        int yy=y;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            gai(1,1,n,id[top[x]],id[x],k);
            x=fa[top[x]];
        //    cout<<4554545;
        }
        if(dep[x]>dep[y]) swap(x,y);
        gai(1,1,n,id[x],id[y],k);
        gai(1,1,n,id[yy],id[yy],-k);
    }
    void de(int node,int left,int right)
    {
        if(left==right) 
        {
            ansk[yuan[left]]=sum[node];
            //cout<<node<<endl;
            return;
        }
        int mid=(left+right)/2;
        xia(node,mid-left+1,right-mid);
        de(ll(node),left,mid);
        de(rr(node),mid+1,right);
    }
    int main()
    {
        int m,r,x,y;
        cin>>n;
        for(int i=1;i<=n;i++)
        w[i]=0;
        for(int i=1;i<=n;i++)
        scanf("%d",&kkk[i]);
        for(int i=1;i<=n-1;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs1(1,0,1);
        dfs2(1,1);
        for(int i=1;i<n;i++)
        {    
            gai1(kkk[i],kkk[i+1],1);
        }
        de(1,1,n);
        for(int i=1;i<=n;i++)
        printf("%d
    ",ansk[i]);
    }
  • 相关阅读:
    Mac下配置phpredis扩展
    PHP 面向对象中常见关键字使用(final、static、const和instanceof)
    PHP null常量和null字节的区别
    PHP关于时区问题
    C++指针的操作和运算(转)
    浅谈C++中指针和引用的区别者之间的区别和用法(转)
    rails Rendering Text 用法
    MySQL“慢SQL”定位
    数组循环移位问题
    core文件问题
  • 原文地址:https://www.cnblogs.com/kzj-pwq/p/8179689.html
Copyright © 2020-2023  润新知