zoukankan      html  css  js  c++  java
  • 【BZOJ3307】雨天的尾巴-线段树合并+树上差分

    测试地址:雨天的尾巴
    题目大意:一棵树,对其执行若干次操作,每次选定一条路径和一种型号的货物,然后给这条路径上所有的点派发一份选定型号的货物,最后求每个点获得的最多的货物的型号。
    做法:本题需要用到线段树合并+树上差分。
    首先,对一条路径派发货物,我们可以用树上差分的思想,将其转化为向路径的两个端点派发一份货物,然后向LCA和LCA的父亲派发负一份货物,那么每个点的货物相当于其子树中所有货物的和。要维护所有货物出现次数的最大值显然可以用线段树,那么我们就先按照操作对每一个点维护线段树,然后自底向上合并出每棵子树的线段树即可,复杂度应该在O(nlogn)O(nlog2n)之间,具体本人也不太会证明……
    注意货物的序号可能很大,离散化一下就可以了。
    以下是本人代码:

    #include <bits/stdc++.h>
    #define inf 1000000000
    using namespace std;
    int n,m,x[100010],y[100010],z[100010],fa[100010][21],dep[100010],rt[100010]={0},q[100010];
    int first[100010]={0},tot=0,totp=0,mx[5000010],mxp[5000010],ch[5000010][2],ans[100010];
    struct forsort
    {
        int id,val;
    }f[100010];
    struct edge
    {
        int v,next;
    }e[200010];
    
    void insert(int a,int b)
    {
        e[++tot].v=b,e[tot].next=first[a],first[a]=tot;
    }
    
    bool cmp(forsort a,forsort b)
    {
        return a.val<b.val;
    }
    
    void dfs(int v)
    {
        for(int i=first[v];i;i=e[i].next)
            if (e[i].v!=fa[v][0])
            {
                fa[e[i].v][0]=v;
                dep[e[i].v]=dep[v]+1;
                dfs(e[i].v);
            }
    }
    
    int lca(int x,int y)
    {
        if (dep[x]<dep[y]) swap(x,y);
        for(int i=20;i>=0;i--)
            if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
        if (x==y) return x;
        for(int i=20;i>=0;i--)
            if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    void pushup(int x)
    {
        if (!ch[x][0]) {mx[x]=mx[ch[x][1]],mxp[x]=mxp[ch[x][1]];return;}
        if (!ch[x][1]) {mx[x]=mx[ch[x][0]],mxp[x]=mxp[ch[x][0]];return;}
        mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);
        if (mx[ch[x][0]]>mx[ch[x][1]]) mxp[x]=mxp[ch[x][0]];
        else if (mx[ch[x][0]]<mx[ch[x][1]]) mxp[x]=mxp[ch[x][1]];
             else mxp[x]=min(mxp[ch[x][0]],mxp[ch[x][1]]);
    }
    
    void treeinsert(int &v,int l,int r,int x,int add)
    {
        if (!v) v=++totp,mx[v]=-inf,mxp[v]=ch[v][0]=ch[v][1]=0;
        if (l==r)
        {
            if (mx[v]==-inf) mx[v]=0;
            mx[v]+=add,mxp[v]=x;
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid) treeinsert(ch[v][0],l,mid,x,add);
        else treeinsert(ch[v][1],mid+1,r,x,add);
        pushup(v);
    }
    
    void merge_leaf(int x,int y)
    {
        mx[x]+=mx[y];
    }
    
    void merge(int &x,int y)
    {
        if (!x) {x=y;return;}
        if (!y) return;
        merge(ch[x][0],ch[y][0]);
        merge(ch[x][1],ch[y][1]);
        if (!ch[x][0]&&!ch[x][1]) merge_leaf(x,y);
        else pushup(x);
    }
    
    void solve(int v)
    {
        for(int i=first[v];i;i=e[i].next)
            if (e[i].v!=fa[v][0])
            {
                solve(e[i].v);
                merge(rt[v],rt[e[i].v]);
            }
        if (mx[rt[v]]>0) ans[v]=q[mxp[rt[v]]];
        else ans[v]=0;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            insert(a,b),insert(b,a);
        }
    
        fa[1][0]=fa[0][0]=0;dep[1]=0,dep[0]=-1;
        dfs(1);
        for(int i=1;i<=20;i++)
            for(int j=1;j<=n;j++)
                fa[j][i]=fa[fa[j][i-1]][i-1];
    
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x[i],&y[i],&z[i]);
            f[i].id=i,f[i].val=z[i];
        }
    
        sort(f+1,f+m+1,cmp);
        tot=0;
        for(int i=1;i<=m;i++)
        {
            if (i==1||f[i].val!=f[i-1].val) q[++tot]=f[i].val;
            z[f[i].id]=tot;
        }
    
        for(int i=1;i<=m;i++)
        {
            int g=lca(x[i],y[i]);
            treeinsert(rt[x[i]],1,tot,z[i],1);
            treeinsert(rt[y[i]],1,tot,z[i],1);
            treeinsert(rt[g],1,tot,z[i],-1);
            if (g!=1) treeinsert(rt[fa[g][0]],1,tot,z[i],-1);
        }
    
        solve(1);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans[i]);
    
        return 0;
    }
  • 相关阅读:
    用asp自编源码制作动态的音乐播放页面
    VBS 连接数据库 样例
    VBS访问SQL数据库
    人人都应该知道的计算机网络协议(1)
    VBS 访问数据库 别人写的一份公共函数
    WPF DateTimePicker 和 TimeSpanPicker 控件发布
    实现Evernote的OAuth授权
    EvernoteTodo发布
    EvernoteAdage 发布
    关于 极限(Extreme)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793511.html
Copyright © 2011-2022 走看看