[JZOJ3397]【GDOI2014模擬】雨天的尾巴


Description

深繪里一直很討厭雨天。

灼熱的天氣穿透了前半個夏天,后來一場大雨和隨之而來的洪水,澆滅了一切。

雖然深繪里家鄉的小村落對洪水有着頑固的抵抗力,但也倒了幾座老房子,幾棵老樹被連

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

無奈的深繪里和村民們只好等待救濟糧來維生。

不過救濟糧的發放方式很特別。

首先村落里的一共有n 座房屋,並形成一個樹狀結構。然后救濟糧分m 次發放,每次選擇

兩個房屋(x,y),然后對於x 到y 的路徑上(含x 和y) 每座房子里發放一袋z 類型的救濟糧。

然后深繪里想知道,當所有的救濟糧發放完畢后,每座房子里存放的最多的是哪種救濟糧

Solution

一道樹上路徑修改問題

比較惡心的是,最多有 100000 種救濟糧

我們先考慮在一個序列上區間修改

把每個區間左邊界排序,左邊界+1,右邊界-1,從左到右掃一遍扔進堆里,然后堆頂就是當前答案

放到樹上可以樹鏈剖分,對於每個鏈操作都是獨立的,分開處理就好。

但是,你有沒有覺得很麻煩?

仔細研究題目,發現詢問並不是動態的。

對於樹上每一個點,都維護一個動態開點的以種類為下標的權值線段樹,記錄最大值和位置。

顯然我們不能每個操作都去路徑維護。

對於下面這個圖
這里寫圖片描述

對於多次路徑修改,有一種十分經典的做法——線段樹合並

關於線段樹合並不理解的可以看這里

我們需要對 x,y 進行路徑修改,那么可以將 x,y 都加上1
lca(x,y),fa[lca(x,y)] 都減1

想想為什么 fa[lca(x,y)] 也要減1?

這樣到了最后線段樹合並的時候,從葉子節點向根逐漸合並,到了 lca(x,y) 的時候就會有 x,y 的影響之和,所以要減去1,在 fa[lca(x,y)] 減1是為了讓 lca(x,y) 以上不受影響

這樣可以 logMaxz 修改, NlogMaxz 合並的

有人可能會有疑問,不是每個點都要開一個權值線段樹 NlogMaxz 空間?合並時候更是 NMlogMaxz ?

不虛,我們有動態開節點!
因為每次操作最多新開 4logMaxz 個節點,最后最多總共也只有 4MlogMaxz 個,

合並時並不需要多開節點,詳見上面鏈接

於是我們在 O(NlogMaxz) 復雜度內解決,然而鏈剖是需要 O(Nlog2N)

Code

本人特別討厭線段樹,因為每次我都把線段樹打的很長很長~~

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define fo1(i,a) for(int i=last[k];i;i=next[i])
using namespace std;
struct note
{
    int l,r,mx,wz,ls,rs;    
};
struct note1
{
    int x,y,z;
};
bool cmp(note1 x,note1 y)
{
    return x.z<y.z;
}
note tree[5000000];
int next[200005],dt[200005],last[100005],first[100005];
int n,m,a1[100005][2],ft[100005][17],root[100005],deep[100005],lim,dp,rlim,maxn;
int pt[100001];
note1 cz[100001];

void dfs(int k,int f)
{
    ft[k][0]=f;
    deep[k]=deep[f]+1;
    dp=deep[k];
    if (deep[k]==43423)
    {
        dp++;
        dp--;
    }
    fo1(b,k) 
        if (dt[b]!=f) dfs(dt[b],k);  
} 
int lca(int x,int y)
{
    if (deep[x]<deep[y]) swap(x,y);
    while(deep[x]!=deep[y])
    {
        int i=0; 
        while(deep[ft[x][i]]>=deep[y]) i++;
        x=ft[x][--i];
    }
    while (x!=y)
    {
        int i=0;
        while (ft[x][i]!=ft[y][i]) i++;
        if (i==0) return ft[x][0];
        x=ft[x][--i];
        y=ft[y][i];
    }
    return x;
}
void buildl(int now,int l,int r)
{
    if (tree[now].ls==0)
    {
        tree[now].ls=++lim;
        tree[lim].l=l;
        tree[lim].r=r;
    }
}
void buildr(int now,int l,int r)
{
    if (tree[now].rs==0)
    {
        tree[now].rs=++lim;
        tree[lim].l=l;
        tree[lim].r=r;
    }
}
void change(int now,int l,int r,int v)
{
    if (tree[now].l==l&&tree[now].r==r)
    {
        tree[now].mx+=v;
        tree[now].wz=l;
        return; 
    }
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)
    {
        buildl(now,tree[now].l,mid);
        change(tree[now].ls,l,r,v);
    } 
    else if (l>mid)
    {
        buildr(now,mid+1,tree[now].r);
        change(tree[now].rs,l,r,v);
    }
    else
    {
        buildl(now,tree[now].l,mid);
        buildr(now,mid+1,tree[now].r);
        change(tree[now].ls,l,mid,v);
        change(tree[now].rs,mid+1,r,v);
    }
    int ls=tree[now].ls,rs=tree[now].rs;
    int x=tree[ls].mx,y=tree[rs].mx,x1=tree[ls].wz,y1=tree[rs].wz;
    tree[now].mx=(x>=y)?x:y;
    tree[now].wz=(x>=y)?x1:y1; 
}
void hb(int hf,int hs,int l,int r)
{
    if(l==r)
    {
        tree[hf].mx+=tree[hs].mx;
        tree[hf].wz=l;
        return;
    }
    int lsf=tree[hf].ls,rsf=tree[hf].rs,lss=tree[hs].ls,rss=tree[hs].rs,mid=(l+r)/2;
    if (lss!=0)
    {
        if (lsf==0) tree[hf].ls=lss;
        else hb(lsf,lss,l,mid);  
    } 
    if (rss!=0)
    {
        if (rsf==0) tree[hf].rs=rss;
        else hb(rsf,rss,mid+1,r);
    }
    int x=tree[tree[hf].ls].mx,y=tree[tree[hf].rs].mx,x1=tree[tree[hf].ls].wz,y1=tree[tree[hf].rs].wz;
    tree[hf].mx=(x>=y)?x:y;
    tree[hf].wz=(x>=y)?x1:y1; 
}
void merge(int k,int f)
{
    int i;
    for(int i=last[k];i;i=next[i])
    {
        if (dt[i]!=f)
        {
            merge(dt[i],k);
            hb(root[k],root[dt[i]],1,maxn);
        }   
    }
}
int main()
{
    cin>>n>>m;
    int i,j;
    rlim=0;
    fo(i,1,n-1) 
    {
        int x,y;
        rlim++;
        scanf("%d%d",&x,&y);
        dt[rlim]=x;
        if (last[y]==0) last[y]=first[y]=rlim;
        else 
        {
            next[first[y]]=rlim;
            first[y]=rlim;
        }
        rlim++;
        dt[rlim]=y;
        if (last[x]==0) last[x]=first[x]=rlim;
        else 
        {
            next[first[x]]=rlim;
            first[x]=rlim;
        }
    }
    dfs(1,0);
    fo(i,1,trunc(log(n)/log(2)))
        fo(j,1,n) ft[j][i]=ft[ft[j][i-1]][i-1];
    fo(i,1,m)
    {
        int x,y,z;
        scanf("%d%d%d",&cz[i].x,&cz[i].y,&cz[i].z);
        maxn=100000;
    }
    sort(cz+1,cz+m+1,cmp);
    int bi=0;
    fo(i,1,n) 
    {
        root[i]=++lim;
        tree[lim].l=1;
        tree[lim].r=100000;
    }
    fo(i,1,m)
    {
        if (cz[i].z!=cz[i-1].z) bi++;
        pt[bi]=cz[i].z;
        int x=cz[i].x,y=cz[i].y;
        int lp=lca(x,y);
        change(root[x],bi,bi,1);
        change(root[y],bi,bi,1);
        change(root[lp],bi,bi,-1);
        if (lp!=1) change(root[ft[lp][0]],bi,bi,-1);
    }
    merge(1,0);
    fo(i,1,n) printf("%d\n",pt[tree[root[i]].wz]);
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com