1. 程式人生 > >[bzoj4860] [BeiJing2017]樹的難題

[bzoj4860] [BeiJing2017]樹的難題

Description

給你一棵 n 個點的無根樹。樹上的每條邊具有顏色。 一共有 m 種顏色,編號為 1 到 m。第 i 種顏色的權值為

ci。對於一條樹上的簡單路徑,路徑上經過的所有邊按順序組成一個顏色序列,序列可以劃分成若干個相同顏色段

。 定義路徑權值為顏色序列上每個同顏色段的顏色權值之和。請你計算,經過邊數在 l 到 r 之間的所有簡單路

徑中, 路徑權值的最大值。

Input

第一行, 四個整數 n, m, l, r。

第二行, n 個整數 c1, c2, ……, cm,由空格隔開。依次表示每個顏色的權值。

接下來 n-1 行,每行三個整數 u, v, c,表示點 u 和點 v 之間有一條顏色為 c 的邊。

Output

輸出一行, 一個整數, 表示答案。

Sample Input

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

Sample Output

-1

Solution

統計鏈上資訊,上點分治。

對於當前的分治中心,把邊按顏色\(sort\)一遍,然後開兩個線段樹,對於顏色相同的邊用一顆線段樹統計,不同的也開一顆,做完一種顏色就把兩顆線段樹合併一下,然後清空就好了。

複雜度\(O(n\log^2n)\),然後憑藉信仰過掉此題(跑的還蠻快的)

不過正解好像是單調佇列,我太弱了不會QAQ

#include<bits/stdc++.h>
using namespace std;

inline int max(int x,int y) {return x>y?x:y;}
#define il inline

il void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
il void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
il void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 6e5+10;
const int inf = 1e9;

int n,m,l,r,tot,st[maxn],ed[maxn],ls[maxn<<2],rs[maxn<<2],tr[maxn<<2],cnt;

struct edge{
    int fr,to,w;
    int operator < (const edge &rhs) const {
        return fr<rhs.fr||(fr==rhs.fr&&w<rhs.w);
    }
}e[maxn<<1];

il void add(int u,int v,int w) {e[++tot]=(edge){u,v,w};}
il void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}

#define mid ((l+r)>>1)

namespace Segment_Tree {
    void modify(int &p,int l,int r,int x,int v) {
        if(!p) p=++cnt,ls[p]=rs[p]=0,tr[p]=-inf;
        else tr[p]=max(tr[p],v);
        if(l==r) return ;
        if(x<=mid) modify(ls[p],l,mid,x,v);
        else modify(rs[p],mid+1,r,x,v);
    }
    int query(int p,int l,int r,int x,int y) {
        if(!p) return -inf;
        if(x<=l&&r<=y) return tr[p];
        int ans=-inf;
        if(x<=mid) ans=max(ans,query(ls[p],l,mid,x,y));
        if(y>mid) ans=max(ans,query(rs[p],mid+1,r,x,y));
        return ans;
    }
    int merge(int x,int y) {
        if(!x||!y) return x+y;
        ls[x]=merge(ls[x],ls[y]);
        rs[x]=merge(rs[x],rs[y]);
        tr[x]=max(tr[x],tr[y]);
        return x;
    }
}

#undef mid 

using namespace Segment_Tree;

namespace Tree {
    int rt,f[maxn],sz[maxn],size,vis[maxn],data_cnt,c[maxn],ans,ss[maxn];

    void get_rt(int x,int fa) {
        sz[x]=1,f[x]=1;
        for(int i=st[x];i<=ed[x];i++)
            if(e[i].to!=fa&&(!vis[e[i].to])) 
                get_rt(e[i].to,x),sz[x]+=sz[e[i].to],f[x]=max(f[x],sz[e[i].to]);
        f[x]=max(f[x],size-sz[x]);
        if(f[rt]>f[x]) rt=x;
    }

    struct data {int dep,dis;}d[maxn];

    void get_data(int x,int fa,int dep,int col,int sum) {
        if(dep>r) return ;
        for(int i=st[x];i<=ed[x];i++) {
            if(e[i].to==fa||vis[e[i].to]) continue;
            d[++data_cnt]=(data){dep+1,sum+((col==e[i].w)?0:c[e[i].w])};
            get_data(e[i].to,x,dep+1,e[i].w,sum+((col==e[i].w)?0:c[e[i].w]));
        }
    }

    void solve(int x) {
        vis[x]=1;int r1=0,r2=cnt=0;
        for(int i=st[x];i<=ed[x];++i) {
            if(e[i].w!=e[i-1].w&&i!=st[x]) r1=merge(r1,r2),r2=0;
            if(vis[e[i].to]) continue;
            data_cnt=0;
            d[++data_cnt]=(data){1,c[e[i].w]};
            get_data(e[i].to,x,1,e[i].w,c[e[i].w]);
            ss[i]=data_cnt;
            for(int j=1;j<=data_cnt;++j) {
                if(d[j].dep>r) continue;
                if(d[j].dep<r) {
                    ans=max(ans,d[j].dis+query(r2,1,n,max(1,l-d[j].dep),r-d[j].dep)-c[e[i].w]);
                    ans=max(ans,d[j].dis+query(r1,1,n,max(1,l-d[j].dep),r-d[j].dep));
                }
                if(d[j].dep>=l) ans=max(ans,d[j].dis);
            }
            for(int j=1;j<=data_cnt;++j)
                if(d[j].dep<r) modify(r2,1,n,d[j].dep,d[j].dis);
        }
        for(int i=st[x];i<=ed[x];++i) {
            if(vis[e[i].to]) continue;
            rt=0,size=ss[i],get_rt(e[i].to,x);
            solve(rt);
        }
    }
}

using namespace Tree;

int main() {
    read(n),read(m),read(l),read(r);ans=-inf;
    for(int i=1;i<=m;i++) read(c[i]);
    for(int i=1,x,y,z;i<n;i++) read(x),read(y),read(z),ins(x,y,z);
    sort(e+1,e+n*2-1);int p=1;
    for(int i=1;i<=n;i++) {
        st[i]=p;while(e[p].fr==i&&p<=n*2-2) p++;ed[i]=p-1;
    }
    rt=0,f[0]=maxn+1,size=n,get_rt(1,0),solve(rt);write(ans);
    return 0;
}