zoukankan      html  css  js  c++  java
  • [树上差分][线段树合并]JZOJ 3397 雨天的尾巴

    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
     

    Data Constraint

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

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

    对于100% 的数据,1 <= n;m <= 100000; 1 <= a, b, x, y <= n; 1 <= z <= 10^9

    分析

    看完T1T2以后看T3

    噔 噔 咚 心 肺 停 止

    又™是树链剖分?有了T1的经验我仔细再看了两眼

    的确是链剖,只是当时没想到奇妙的堆乱搞,然后用链剖打了个暴力……(排序z暴力做链剖,O(nlog+nm)有70?!)

    堆的写法好奇妙,但是我选择简单的树上差分和线段树合并……

    差分就把x,y的z+1,lca的z-1,fa[lca]的z-1即可

    最后自底向上统计答案,顺便合并线段树

    (居然要我写BFS用深度来处理防爆栈?)

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #define lson ls[x]
    #define rson rs[x]
    using namespace std;
    const int N=1e5+10;
    const int Inf=1e9;
    struct Graph {
        int v,nx;
    }g[2*N];
    int cnt,list[N];
    int t[100*N],ls[100*N],rs[100*N],scnt,root[N],f[N][20],dep[N];
    int n,m,ans[N],a[N];
    
    void Add(int u,int v) {
        g[++cnt]=(Graph){v,list[u]};list[u]=cnt;
        g[++cnt]=(Graph){u,list[v]};list[v]=cnt;
    }
    
    void BFS(int v0) {
        queue<int> q;
        while (!q.empty()) q.pop();
        q.push(v0);
        while (!q.empty()) {
            int u=q.front();q.pop();
            for (int i=list[u];i;i=g[i].nx)
                if (g[i].v!=f[u][0]) {
                    f[g[i].v][0]=u;dep[g[i].v]=dep[u]+1;
                    q.push(g[i].v);
                }
        }
    }
    
    int LCA(int u,int v) {
        if (dep[u]<dep[v]) swap(u,v);
        for (int i=19;i>=0;i--)
            if (dep[f[u][i]]>=dep[v]) u=f[u][i];
        if (u==v) return v;
        for (int i=19;i>=0;i--)
            if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
        return f[u][0];
    }
    
    void Insert(int &x,int l,int r,int k,int z) {
        if (!x) x=++scnt;
        if (l==r) {
            t[x]+=z;
            return;
        }
        int mid=l+r>>1;
        if (k<=mid) Insert(lson,l,mid,k,z);
        else Insert(rson,mid+1,r,k,z);
        t[x]=max(t[lson],t[rson]);
    }
    
    void Merge(int &x,int y,int l,int r) {
        if (!y) return;
        if (!x) {
            t[x=++scnt]=t[y],lson=ls[y],rson=rs[y];
            return;
        }
        if (l==r) {
            t[x]+=t[y];
            return;
        }
        int mid=l+r>>1;
        Merge(lson,ls[y],l,mid);Merge(rson,rs[y],mid+1,r);
        t[x]=max(t[lson],t[rson]);
    }
    
    int Locate(int x,int l,int r,int mx) {
        if (l==r) return l;
        int mid=l+r>>1;
        if (t[lson]==mx) return Locate(lson,l,mid,mx);
        return Locate(rson,mid+1,r,mx);
    }
    
    bool CMP(int a,int b) {
        return dep[a]>dep[b];
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),Add(u,v),a[i]=i;a[n]=n;
        dep[1]=1;BFS(1);sort(a+1,a+n+1,CMP);
        for (int i=1;i<20;i++)
            for (int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1];
        for (int i=1;i<=m;i++) {
            int x,y,z,lca;
            scanf("%d%d%d",&x,&y,&z);
            lca=LCA(x,y);
            Insert(root[x],0,Inf,z,1);Insert(root[y],0,Inf,z,1);
            Insert(root[lca],0,Inf,z,-1);if (f[lca][0]) Insert(root[f[lca][0]],0,Inf,z,-1);
        }
        for (int i=1;i<n;i++) {
            int u=a[i];
            int mx=t[root[u]];
            ans[u]=Locate(root[u],0,Inf,mx);
            Merge(root[f[u][0]],root[u],0,Inf);
        }
        int mx=t[root[1]];
        ans[1]=Locate(root[1],0,Inf,mx);
        for (int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    为什么 PCB 生产时推荐出 Gerber 给工厂?
    Fedora Redhat Centos 有什么区别和关系?
    【KiCad】 如何给元件给元件的管脚加上划线?
    MCU ADC 进入 PD 模式后出现错误的值?
    FastAdmin 生产环境升级注意
    EMC EMI 自行评估记录
    如何让你的 KiCad 在缩放时不眩晕?
    KiCad 5.1.0 正式版终于发布
    一次单片机 SFR 页引发的“事故”
    java基础之集合
  • 原文地址:https://www.cnblogs.com/mastervan/p/11178410.html
Copyright © 2011-2022 走看看