• JDOJ 1985: [HN3.22]雨天的尾巴


    JDOJ 1985: [HN3.22]雨天的尾巴

    JDOJ传送门

    Description

    灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。

    虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连

    根拔起,以及田地里的粮食被弄得一片狼藉。

    无奈的深绘里和村民们只好等待救济粮来维生。

    不过救济粮的发放方式很特别。

    首先村落里的一共有n 座房屋,并形成一个树状结构。然后救济粮分m 次发放,每次选择

    两个房屋(x,y),然后对于x 到y 的路径上(含x 和y) 每座房子里发放一袋z 类型的救济粮。

    Input

    第一行两个正整数n,m,含义如题目所示。

    接下来n-1 行,每行两个数(a,b),表示(a,b) 间有一条边。

    再接下来m 行,每行三个数(x,y,z),含义如题目所示。

    Output

    n 行,第i 行一个整数,表示第i 座房屋里存放的最多的是哪种救济粮,如果有多种救济粮

    存放次数一样,输出编号最小的。

    如果某座房屋里没有救济粮,则对应一行输出0。

    Sample Input

    5 3 1 2 3 1 3 4 5 4 2 3 3 1 5 2 3 3 3

    Sample Output

    2 3 3 2 2

    HINT

    【数据范围和约定】

    对于20% 的数据,1<n,m <100

    对于50% 的数据,1< n,m< 2000

    对于100% 的数据,1<n,m<100000, 1<a, b, x, y< n, 1<z<109


    题解:

    和洛谷模板题稍有不同:

    就是z变成了1e9,而洛谷的是1e5。

    本来寻思需要离散化。

    但是一想:动态开点啊,所以不用。

    所以代码是一样的:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    char *p1,*p2,buf[100000];
    #define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int read()
    {
        int x=0,f=1;
        char ch=nc();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')
                f=-1;
            ch=nc();
        }
        while(ch>='0'&&ch<='9')
            x=x*10+ch-'0',ch=nc();
       	return x*f;
    }
    const int maxn=1e5+10;
    int n,m,maxx;
    int tot,to[maxn<<1],nxt[maxn<<1],head[maxn];
    int deep[maxn],size[maxn],fa[maxn],top[maxn],son[maxn],root[maxn];
    int lson[maxn*60],rson[maxn*60],sum[maxn*60],wh[maxn*60],cnt;
    //sum存最多救济粮个数,wh存最小编号的最多救济粮种类
    int ans[maxn];
    struct node
    {
        int x,y,z;
    }q[maxn];
    void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    void dfs1(int x,int f)
    {
        deep[x]=deep[f]+1;
        fa[x]=f;
        size[x]=1;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==f)
                continue;
            dfs1(y,x);
            size[x]+=size[y];
            if(!son[x]||size[y]>size[son[x]])
                son[x]=y;
        }
    }
    void dfs2(int x,int t)
    {
        top[x]=t;
        if(!son[x])
            return;
        dfs2(son[x],t);
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==fa[x]||y==son[x])
                continue;
            dfs2(y,y);
        }
    }
    int lca(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])
                swap(x,y);
            x=fa[top[x]];
        }
        return deep[x]<deep[y]?x:y;
    }
    void pushup(int pos)
    {
        if(sum[lson[pos]]>=sum[rson[pos]])
            sum[pos]=sum[lson[pos]],wh[pos]=wh[lson[pos]];
        else
            sum[pos]=sum[rson[pos]],wh[pos]=wh[rson[pos]];
    }
    void update(int &pos,int l,int r,int x,int k)//将数x的个数+k
    {
        int mid=(l+r)>>1;
        if(!pos)
            pos=++cnt;   
        {
            sum[pos]+=k;
            wh[pos]=l;
            return;
        }
        if(x<=mid)
            update(lson[pos],l,mid,x,k);
        else
            update(rson[pos],mid+1,r,x,k);
        pushup(pos);
    }
    void merge(int &x,int y,int l,int r)
    {
        int mid=(l+r)>>1;
        if(!x||!y)
        {
            x=(!x?y:x);
            return;
        }
        if(l==r)
        {
            sum[x]+=sum[y];
            wh[x]=l;
            return;
        }
        merge(lson[x],lson[y],l,mid);
        merge(rson[x],rson[y],mid+1,r);
        pushup(x);
    }
    void dfs(int x)
    {
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==fa[x])
                continue;
            dfs(y);
            merge(root[x],root[y],1,maxx);
        }
        if(sum[root[x]])
            ans[x]=wh[root[x]];
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<n;i++)
        {
            int x,y;
            x=read();y=read();
            add(x,y);
            add(y,x);
        }
        dfs1(1,0);
        dfs2(1,1);
        for(int i=1;i<=m;i++)
        {
            q[i].x=read(),q[i].y=read(),q[i].z=read();
            maxx=max(maxx,q[i].z);
        }
        for(int i=1;i<=m;i++)//树上的每一个节点有一棵权值线段树
        {
            int l=lca(q[i].x,q[i].y);
            update(root[q[i].x],1,maxx,q[i].z,1);
            update(root[q[i].y],1,maxx,q[i].z,1);
            update(root[l],1,maxx,q[i].z,-1);
            if(fa[l])
                update(root[fa[l]],1,maxx,q[i].z,-1);
        }
        dfs(1);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    C#的默认访问权限
    隐藏基类成员
    索引指示器的重载
    索引指示器
    vector
    string 函数
    细胞个数
    计蒜客 T1096 石头剪刀布
    计蒜客 T1125 判断字符串是否为回文
    计蒜客 T1152 成绩排序
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13820420.html
Copyright © 2020-2023  润新知