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

Description

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

Solution

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

Code

#include
#include
#include
#include
#include
#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]
    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]
    }
}
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
    }
    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
    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
                o=find(0,w,r-a[j].len)+a[j].sum;
                ans=(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
                o=find(1,w,r-a[j].len)+a[j].sum-c[a[j].se];
                ans=(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
    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);
}

你可能感兴趣的:(省选,树状数组,树分治)