• 洛谷 P3258 BZOJ 3631 [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

    解题思路

      树链剖分,几乎和USACO的某题一毛一样,不同之处在于,这题路径中途的点会重复计算,输出结果不为零时要减一,而且最后一个点不用放糖果。

      我写的树剖+线段树,常数贼大,洛谷上不开O2的话#4就跑不过,可能树剖+树状数组,或者把结构体拆成数组会好一些。正解是树上差分,不会……

    源代码

    #include<bits/stdc++.h>
    
    int n;
    
    struct Edge{
        int nxt,to;
    }e[600010];
    int head[300010]={0},cnt=1;
    void add(int u,int v)
    {
        e[cnt]={head[u],v};
        head[u]=cnt++;
        e[cnt]={head[v],u};
        head[v]=cnt++;
    }
    
    struct Tree{
        int fa;
        int dep;
        int num_to;
        int wson;
        int new_id;
        int top;
    }t[300010];
    int id=1;
    void dfs1(int fa,int u,int dep)
    {
        t[u].fa=fa;
        t[u].dep=dep;
        t[u].num_to=1;
        t[u].wson=-1;
        int max_to=0,num_son=0;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(v==fa) continue;
            num_son++;
            dfs1(u,v,dep+1);
            int temp=t[v].num_to;
            t[u].num_to+=temp;
            if(temp>max_to) t[u].wson=v,max_to=temp;
        }
    }
    void dfs2(int u,int top)
    {
        t[u].top=top;
        t[u].new_id=id;
        id++;
        if(t[u].wson==-1) return;
        dfs2(t[u].wson,top);
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(v==t[u].fa||v==t[u].wson) continue;
            dfs2(v,v);
        }
    }
    
    #define lson(x) ((x)<<1)
    #define rson(x) ((x)<<1|1)
    struct Seg_tree{
        int l,r;
        int sum;
    }s[1200010];
    int lazy[1200010]={0};
    void pushdown(int x)
    {
        int temp=lazy[x];
        lazy[x]=0;
        int ls=lson(x),rs=ls|1;
        s[ls].sum+=temp*(s[ls].r-s[ls].l+1);
        lazy[ls]+=temp;
        s[rs].sum+=temp*(s[rs].r-s[rs].l+1);
        lazy[rs]+=temp;
    }
    void maketree(int x,int l,int r)
    {
        s[x].l=l,s[x].r=r;
        if(l==r)
        {
            s[x].sum=0;
            return;
        }
        int mid=l+r>>1;
        maketree(lson(x),l,mid);
        maketree(rson(x),mid+1,r);
        s[x].sum=0;
    }
    
    void update(int x,int l,int r,int k)
    {
        if(s[x].l>r||s[x].r<l) return;
        if(l<=s[x].l&&s[x].r<=r)
        {
            s[x].sum+=k*(s[x].r-s[x].l+1);
            lazy[x]+=k;
            return;
        }
        if(lazy[x]) pushdown(x);
        update(lson(x),l,r,k);
        update(rson(x),l,r,k);
        s[x].sum=s[lson(x)].sum+s[rson(x)].sum;
    }
    
    int query(int x,int l,int r)
    {
        if(s[x].l>r||s[x].r<l) return 0;
        if(l<=s[x].l&&s[x].r<=r)
            return s[x].sum;
        if(lazy[x]) pushdown(x);
        return query(lson(x),l,r)+query(rson(x),l,r);
    }
    
    void add_path(int x,int y)
    {
        while(t[x].top!=t[y].top)
        {
            if(t[t[x].top].dep<t[t[y].top].dep) std::swap(x,y);
            int xtop=t[x].top;
            update(1,t[xtop].new_id,t[x].new_id,1);
            x=t[xtop].fa;
        }
        if(t[x].new_id<t[y].new_id) std::swap(x,y);
        update(1,t[y].new_id,t[x].new_id,1);
    }
    int a[300010]={0};
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1,u,v;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        dfs1(0,1,1);
        dfs2(1,1);
        maketree(1,1,n);
        for(int i=1;i<n;i++)
            add_path(a[i],a[i+1]);
        for(int i=1;i<=n;i++)
        {
            int ans=query(1,t[i].new_id,t[i].new_id);
            if(ans==0||i==a[1]);
            else ans--;
            printf("%d
    ",ans);
        }
        return 0;
    }

    吐槽

      退役后暑假一个月没碰电脑了,即将进入高三,在开学前夜最后做一道题吧,可能一直到高考这283天都不能刷题了……伤心……

      手有些生疏了,敲了5个*时。但是退役前也要敲好久来着。码力不够,思考、敲代码速度太慢,也难怪OI大赛一直不顺了。

      拼一把高考,把OI先放一放,等拼到不错的大学,ACM时再重新拾起吧!

  • 相关阅读:
    airpods2连接win10的方法步骤
    JSON学习笔记
    TCP-IP总线与CAN总线优缺点对比
    svn切换目录
    SQLite学习笔记
    python-opencv安装及入门
    python数据可视化
    python-opencv视觉巡线
    python-opencv进阶应用
    QT窗口和部件
  • 原文地址:https://www.cnblogs.com/wawcac-blog/p/7437779.html
Copyright © 2020-2023  润新知