1. 程式人生 > >【GDOI2014模擬】雨天的尾巴

【GDOI2014模擬】雨天的尾巴

lca 打出 房子 include 動態 合並操作 return why 以及

題目

深繪裏一直很討厭雨天。
灼熱的天氣穿透了前半個夏天,後來一場大雨和隨之而來的洪水,澆滅了一切。
雖然深繪裏家鄉的小村落對洪水有著頑固的抵抗力,但也倒了幾座老房子,幾棵老樹被連
根拔起,以及田地裏的糧食被弄得一片狼藉。
無奈的深繪裏和村民們只好等待救濟糧來維生。
不過救濟糧的發放方式很特別。
首先村落裏的一共有n 座房屋,並形成一個樹狀結構。然後救濟糧分m 次發放,每次選擇
兩個房屋(x,y),然後對於x 到y 的路徑上(含x 和y) 每座房子裏發放一袋z 類型的救濟糧。
然後深繪裏想知道,當所有的救濟糧發放完畢後,每座房子裏存放的最多的是哪種救濟糧。

分析

相信大多數人都跟我一樣,看到這道題,果斷認為是樹鏈剖分。

其實不然(我1.5h把熟練剖分打出來,以為能過50%。結果打錯了,20%。然後。。。打暴力的人都是50%,#%……&*)。
我們註意到z<=10^9,那麽的數據範圍。
但是m<=100000,所以就先做個離散化。
。。。
接著用到個很神奇的東西,叫線段樹合並。
對於樹上的每一個節點開一棵線段樹,記錄該節點的每個z的數量以及某一段z的最大值。註意要動態開節點,否則會爆空間。
發現,如果要修改從
xy的路徑,其實就是將x的z值加一,y的z值加一,lca(x,y)的z值減一以及fa[lca(x,y)]的z值減一(why?因為當線段樹合並後從xlca(x,y)的路徑上和從ylca(x,y)的路徑上的每個節點的z值都加一,但
lca(x,y)這個節點重復加了,那麽就減掉。不過剩余的z值還會繼續上傳,所以在fa[lca(x,y)]**就把上傳的z值減去)
合並操作

int mesh(int x,int y,int l,int r)
{
    if(l==r)
    {
        tree[x].v+=tree[y].v;
        return 0;                                                    
    }
    int mid=(l+r)/2;
    if(tree[y].l)
    {
        if(!tree[x].l)
            tree[x].l=tree[y].l;
            else
        mesh(tree[x].l,tree[y].l,l,mid);
    }
    if(tree[y].r)
    {
        if(!tree[x].r)
            tree[x].r=tree[y].r;
            else
        mesh(tree[x].r,tree[y].r,mid+1,r);
    }
    tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v);
}

當然,當所有的修改操作做完後才線段樹合並,否則會超時。


#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
using namespace std;
struct trees
{
    int l,r,v;
}tree[8000000];
struct read
{
    int x,y,z;
}re[110000];
int next[201000],last[201000],to[201000],po,tot,n,m,g[200000][20],t[200000],deep[200000],f[200000],sum,ans[2000000];
bool cmp(read x,read y)
{
    return x.z<y.z;
}
int bj(int x,int y)
{
    next[++tot]=last[x];
    last[x]=tot;
    to[tot]=y;
}
int dg(int x)
{
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=g[x][0])
        {
            deep[j]=deep[x]+1;
            g[j][0]=x;
            dg(j);
        }
    }
}
int prelca()
{
    for(int j=1;j<=log2(n);j++)
    {
        for(int i=1;i<=n;i++)
        {
            g[i][j]=g[g[i][j-1]][j-1];
        }
    }
}
int lca(int x,int y)
{
    if(deep[x]>deep[y])
    {
        x=x^y;
        y=x^y;
        x=x^y;
    }
    for(int i=log2(n);i>=0;i--)
    {
        if(deep[g[y][i]]>deep[x])
            y=g[y][i];
    }
    if(deep[y]!=deep[x]) y=g[y][0];
    for(int i=log2(n);i>=0;i--)
    {
        if(g[y][i]!=g[x][i])
        {
            y=g[y][i];
            x=g[x][i];
        }
    }
    if(x!=y) y=g[y][0];
    return y;
}
int put(int v,int l,int r,int x,int y)
{
    if(l==r)
    {
        tree[v].v+=y;
        return 0;
    }
    int mid=(l+r)/2;
    if(x<=mid)
    {
        if(!tree[v].l)
            tree[v].l=++sum;
        put(tree[v].l,l,mid,x,y);
    }
    else
    {
        if(!tree[v].r)
            tree[v].r=++sum;
        put(tree[v].r,mid+1,r,x,y); 
    }
    tree[v].v=max(tree[tree[v].l].v,tree[tree[v].r].v);
}
int work(int x,int y,int z)
{
    int lc=lca(x,y);
    if(!f[x])
    {
        f[x]=++sum;
    }
    put(f[x],1,tot,z,1);
    if(!f[y])
    {
        f[y]=++sum;
    }
    put(f[y],1,tot,z,1);
    if(!f[lc])
    {
        f[lc]=++sum;
    }
    put(f[lc],1,tot,z,-1);
    if(g[lc][0])
    {
        if(!f[g[lc][0]]) f[g[lc][0]]=++sum;
        put(f[g[lc][0]],1,tot,z,-1);
    }
}
int mesh(int x,int y,int l,int r)
{
    if(l==r)
    {
        tree[x].v+=tree[y].v;
        return 0;                                                    
    }
    int mid=(l+r)/2;
    if(tree[y].l)
    {
        if(!tree[x].l)
            tree[x].l=tree[y].l;
            else
        mesh(tree[x].l,tree[y].l,l,mid);
    }
    if(tree[y].r)
    {
        if(!tree[x].r)
            tree[x].r=tree[y].r;
            else
        mesh(tree[x].r,tree[y].r,mid+1,r);
    }
    tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v);
}
int find(int v,int l,int r)
{
    if(l==r)
    {
        return l;
    }
    if(tree[tree[v].l].v==0 && tree[tree[v].r].v==0)
        return 0;
    int mid=(l+r)/2;
    if(tree[tree[v].l].v>=tree[tree[v].r].v)
    {
        return find(tree[v].l,l,mid);
    }
    else
    {
        return find(tree[v].r,mid+1,r); 
    }
}
int merge(int x)
{
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=g[x][0])
        {
            merge(j);
            if(!f[x])
            {       
                f[x]=++sum;
            }   
            if(!f[j])
            {       
                f[j]=++sum;
            }
            mesh(f[x],f[j],1,tot);
        }
    }
    ans[x]=find(f[x],1,tot);
}
int main()
{
    scanf("%d",&n);
    scanf("%d",&m);
    for(int i=1;i<=n-1;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        bj(x,y);
        bj(y,x);
    }
    deep[1]=1;
    dg(1);
    prelca();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&re[i].x,&re[i].y,&re[i].z);
    }
    sort(re+1,re+m+1,cmp);
    tot=0;
    sum=0;
    for(int i=1;i<=m;i++)
    {
        if(re[i].z==t[tot])
        {
            re[i].z=tot;
        }
        else
        {
            t[++tot]=re[i].z;
            re[i].z=tot;
        }
    }
    for(int i=1;i<=m;i++)
    {
        work(re[i].x,re[i].y,re[i].z);
    }
    merge(1);
    for(int i=1;i<=n;i++)
    {
        if(!f[i])
        {       
            f[i]=++sum;
        }   
        printf("%d\n",t[ans[i]]);
    }
}

【GDOI2014模擬】雨天的尾巴