【JZOJ5077】【GDOI2017第三轮模拟day2】树的难题

Description

【JZOJ5077】【GDOI2017第三轮模拟day2】树的难题_第1张图片

Data Constraint

【JZOJ5077】【GDOI2017第三轮模拟day2】树的难题_第2张图片

Solution

这还是一道树分治的题。我们觉得相同颜色很麻烦,所以我们可以在当前的分治重心中先把与重心相连的边按颜色排个序,然后处理出每棵树到根路径上的颜色权值。维护两颗线段树,一颗表示与当前走的儿子颜色不同的答案,一颗表示颜色相同的答案。颜色改变时用线段树合并一下即可。时间复杂度O(Nlog2N).

Code

#include
#include
#include
#include
#include
using namespace std;
const int maxn=4e5+5;
struct code{
    int sum,l;
}d[maxn],b[maxn],c1[maxn];
struct code1{
    int bz,mx;
}f[maxn*4],g[maxn*4];
int first[maxn],last[maxn],next[maxn],value[maxn],c[maxn],size[maxn],mx[maxn],bz[maxn],fa[maxn];
int n,m,i,j,t,k,l,x,y,z,r,num,ans,p,num1,num2,mx1;
void lian(int x,int y,int z){
    last[++num]=y;next[num]=first[x];first[x]=num;value[num]=z;
}
bool cmp(code x,code y){
    return x.sum<y.sum;
}
void find(int l,int r,int v,int x,int y,int bz){
    int mid=(l+r)/2;
    if (f[v].bz!=bz) return;
    if (l>=x && r<=y){
        k=max(k,f[v].mx);return;
    }
    if (l<=y && mid>=x) find(l,mid,v*2,x,y,bz);
    if (mid<y && r>=x) find(mid+1,r,v*2+1,x,y,bz);
}
void find1(int l,int r,int v,int x,int y,int bz){
    int mid=(l+r)/2;
    if (g[v].bz!=bz) return;
    if (l>=x && r<=y){
        k=max(k,g[v].mx);return;
    }
    if (l<=y && mid>=x) find1(l,mid,v*2,x,y,bz);
    if (mid<y && r>=x) find1(mid+1,r,v*2+1,x,y,bz);
}
void make(int v,int bz){
    f[v].mx=-2e9;
    if (f[v*2].bz==bz) f[v].mx=f[v*2].mx;
    if (f[v*2+1].bz==bz) f[v].mx=max(f[v].mx,f[v*2+1].mx);
}
void make1(int v,int bz){
    g[v].mx=-2e9;
    if (g[v*2].bz==bz) g[v].mx=g[v*2].mx;
    if (g[v*2+1].bz==bz) g[v].mx=max(g[v].mx,g[v*2+1].mx);
}
void insert1(int l,int r,int v,int y,int x,int bz){
    int mid=(l+r)/2;
    if (g[v].bz!=bz) g[v].mx=-2e9,g[v].bz=bz;
    if (l==r){
        g[v].mx=max(y,g[v].mx);return;
    }
    if (mid>=x) insert1(l,mid,v*2,y,x,bz);
    else insert1(mid+1,r,v*2+1,y,x,bz);
    make1(v,bz);
}
void insert(int l,int r,int v,int y,int x,int bz){
    int mid=(l+r)/2;
    if (f[v].bz!=bz) f[v].mx=-2e9,f[v].bz=bz;
    if (l==r){
        f[v].mx=max(y,f[v].mx);return;
    }
    if (mid>=x) insert(l,mid,v*2,y,x,bz);
    else insert(mid+1,r,v*2+1,y,x,bz);
    make(v,bz);
}
void dg1(int x,int y){
    int t;size[x]=1,mx[x]=0;
    for (t=first[x];t;t=next[t]){
        if (bz[last[t]] || last[t]==y) continue;
        dg1(last[t],x);size[x]+=size[last[t]];mx[x]=max(mx[x],size[last[t]]);
    }
}
void dg2(int x,int y){
    int t,k=num;
    if (d[k].l==r) return;
    for (t=first[x];t;t=next[t]){
        if (bz[last[t]] || last[t]==y) continue;
        d[++num].l=d[k].l+1;d[num].sum=d[k].sum;
        if (value[t]!=fa[x]) d[num].sum+=c[value[t]];fa[last[t]]=value[t];
        dg2(last[t],x); 
    }
}
int find(int x,int y){
    int t,k;
    if (max(mx[x],p-size[x])*2<=p || p==1) return x;
    for (t=first[x];t;t=next[t]){
        if (bz[last[t]] || last[t]==y) continue;
        k=find(last[t],x);if (k) return k;
    }
    return 0;
}
void dg(int x){
    dg1(x,0);p=size[x];
    if (mx1*p<=ans) return;
    x=find(x,0);
    bz[x]=1;int t;num=0;
    for (t=first[x];t;t=next[t]){
        if (bz[last[t]]) continue;
        b[++num].sum=value[t];b[num].l=last[t];
    }
    sort(b+1,b+num+1,cmp);num2=num;
    for (i=1;i<=num2;i++){
        d[num=1].sum=c[b[i].sum];d[1].l=1;fa[b[i].l]=b[i].sum;
        dg2(b[i].l,x);
        for (j=1;j<=num;j++){
            k=-2e9;
            find(1,n,1,max(1,l-d[j].l),r-d[j].l,x);
            find1(1,n,1,max(1,l-d[j].l),r-d[j].l,b[i].sum);
            if (k!=-2e9)ans=max(ans,k+d[j].sum);
            if (d[j].l>=l) ans=max(ans,d[j].sum);
            c1[++num1]=d[j];
        }
        for (j=1;j<=num;j++)
            insert1(1,n,1,d[j].sum-c[b[i].sum],d[j].l,b[i].sum);
        if (b[i+1].sum!=b[i].sum){
            while (num1) insert(1,n,1,c1[num1].sum,c1[num1].l,x),num1--;
        }
    }
    for (t=first[x];t;t=next[t])
        if (!bz[last[t]]) dg(last[t]);
}
int main(){
    freopen("journey.in","r",stdin);freopen("journey.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&l,&r);mx1=-2e9;
    for (i=1;i<=m;i++)
        scanf("%d",&c[i]),mx1=max(mx1,c[i]);
    for (i=1;i"%d%d%d",&x,&y,&z),lian(x,y,z),lian(y,x,z);
    p=n;ans=-2e9;
    dg(n/2);printf("%d\n",ans);
}

你可能感兴趣的:(GDOI,树,树分治,机智题,线段树)