【GDOI2017第三轮模拟day2】树的难题(点剖,树状数组)

来源:互联网 发布:linux 重启oracle 编辑:程序博客网 时间:2024/05/16 05:59

Description

这里写图片描述

Solution

一看就知道是点剖,但是还要套上一个数据结构,感觉很麻烦,比赛的时候直接上暴力。
点剖的时候在分治中心的时候,因为发现颜色是一个很麻烦的东西,所以考虑对直系儿子的颜色进行排序,然后对同一个颜色的开一个树状数组,然后对整体开一个树状数组,用树状数组log方的时间求最大值(如果r-lowbit < l那么r–)
这样做是nlog3n的,但是因为树状数组的常数比较小,所以比很多log方线段树的人跑的都快。
但是还是要打一个小优化,如果mx(颜色最大值)*size>ans那么就退出

Code

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define fo(i,a,b) for(i=a;i<=b;i++)#define rep(i,a) for(i=first[a];i;i=next[i])using namespace std;typedef long long ll;const int maxn=2e5+7,inf=0x7fffffff/2;int i,j,k,l,n,m,r,x,y,z,tot,tou,tot1,qian;int c[maxn],first[maxn*2],last[maxn*2],next[maxn*2],chang[maxn*2],num,size[maxn],d[2][maxn];bool bz[maxn],az[2][maxn];ll t[2][maxn],g[2][maxn],o,w,da,dian,ans;struct node{    int se,len;ll sum;}a[maxn];struct nod{    int se,a;}b[maxn];bool cmp(nod x,nod y){return x.se<y.se;}void ad(int x,int y,int z){    last[++num]=y,next[num]=first[x],first[x]=num,chang[num]=z;}void clear(int o){    int i,p;fo(i,1,d[o][0])p=d[o][i],az[o][p]=0,t[o][p]=g[o][p]=-inf;    d[o][0]=0;}void add(int o,int x,ll y){    g[o][x]=(g[o][x]<y)?y:g[o][x];    for(;x<=maxn-7;x+=(x&-x)){        if(!az[o][x])d[o][++d[o][0]]=x,az[o][x]=1;        t[o][x]=(t[o][x]<y)?y:t[o][x];    }}int find(int o,int l,int r){    ll z=-inf;    while(l<=r){        if(r-(r&-r)+1>=l)z=(z<t[o][r])?t[o][r]:z,r-=(r&-r);        else z=(z<g[o][r])?g[o][r]:z,r--;    }    return z;}void dfs1(int x,int y){    int i;size[x]=1;    rep(i,x)if(!bz[last[i]]&&last[i]!=y)dfs1(last[i],x),size[x]+=size[last[i]];}void dfs2(int x,int y){    int i;bool az=1;    rep(i,x)if(!bz[last[i]]&&last[i]!=y){        if(size[last[i]]>dian/2)az=0;        dfs2(last[i],x);    }    if(az&&dian-size[x]<=dian/2)z=x;}void dfs3(int x,int y,int z,int u,ll sum){    int i;    if(z>r)return;    a[++tot]=(node){tou,z,sum};    if(z>=l)ans=(ans<sum)?sum:ans;    rep(i,x){        if(last[i]!=y&&!bz[last[i]]){            if(u==chang[i])dfs3(last[i],x,z+1,u,sum);            else dfs3(last[i],x,z+1,chang[i],sum+c[chang[i]]);        }    }}void fen(int x){    int i,j;    dfs1(x,0);dian=size[x];dfs2(x,0);x=z;bz[x]=1;    if(ans>da*dian)return;    tot1=tot=0;    rep(i,x)if(!bz[last[i]])b[++tot1].se=chang[i],b[tot1].a=last[i];    sort(b+1,b+1+tot1,cmp);    clear(0);    b[++tot1].se=b[tot1-1].se+1;b[0].se=b[1].se;    fo(i,1,tot1){        if(b[i].se!=b[i-1].se){            fo(j,1,tot){                w=(1<l-a[j].len)?l-a[j].len:1;                o=find(0,w,r-a[j].len)+a[j].sum;                ans=(ans<o)?o:ans;            }            if(i==tot1)continue;            fo(j,1,tot)add(0,a[j].len,a[j].sum);tot=0;            clear(1);        }        tou=b[i].se;qian=tot;        dfs3(b[i].a,0,1,b[i].se,c[b[i].se]);        if(b[i].se==b[i-1].se){            fo(j,qian+1,tot){                w=(1<l-a[j].len)?l-a[j].len:1;                o=find(1,w,r-a[j].len)+a[j].sum-c[a[j].se];                ans=(ans<o)?o:ans;            }            fo(j,qian+1,tot)add(1,a[j].len,a[j].sum);        }    }    clear(1);    rep(i,x)if(!bz[last[i]])fen(last[i]);}int main(){    freopen("journey.in","r",stdin);    freopen("journey.out","w",stdout);    scanf("%d%d%d%d",&n,&m,&l,&r);ans=da=-inf;    fo(i,1,m)scanf("%d",&c[i]),da=(da<c[i])?c[i]:da;    fo(i,1,n-1){        scanf("%d%d%d",&x,&y,&z);        ad(x,y,z);ad(y,x,z);        t[0][i]=t[1][i]=g[0][i]=g[1][i]=-inf;    }    fen(n/2);    printf("%lld\n",ans);}
1 0
原创粉丝点击