Description

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

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);
}