您的位置:首页 > 其它

【GDOI2017模拟】树的难题

2017-04-22 21:29 302 查看

Description



Solution

比较明显的树分治,把树分治之后直接对其子树进行处理,因为这道题目并不需要去掉子树的重复贡献,比起其他的一些题就要更好处理了。

对于一个以重心为根的子树,关键在于如何把每一棵子树都合并起来,可以发现要分成两种情况来计算贡献:当前根到子树的颜色与要合并子树的颜色相同或不同,因为相同就要减去重复的边的贡献,为了方便处理,我们要把子树的颜色排序,然后用树状数组维护。

Code

#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define rep(i,x) for(i=la[x];i;i=ne[i])
typedef long long ll;
const int N=2e5+5,INF=-0x7fffffff/3;
struct arr{
int x,se;
}son
;
int node
,da[N*2],ne[N*2],la
,v
,col[N*2];
int t[3]
,T[3]
,d[3]
,de
,lc
,fa
,D
;
ll g
,ans,mx;
int n,m,L,R,i,j,x,y,z,l,r,sum,num,tot,hea;
bool p
,P[3]
,bz
;
bool cmp(arr x,arr y){return x.se<y.se;}
void ins(int x,int y,int z){
da[++sum]=y,ne[sum]=la[x],la[x]=sum,col[sum]=z;
da[++sum]=x,ne[sum]=la[y],la[y]=sum,col[sum]=z;
}
void gnode(int x){
int i,l=0,r=1;D[1]=x;fa[x]=0;
while(l<r){
x=D[++l];
rep(i,x) if(da[i]!=fa[x]&&!p[da[i]]) D[++r]=da[i],fa[da[i]]=x;
}l++;
while(l>1){
x=D[--l];node[x]=1;
rep(i,x) if(da[i]!=fa[x]&&!p[da[i]]) node[x]+=node[da[i]];
}
}
void gheav(int x,int size){
int i,l=0,r=1;bz[x]=1;D[1]=x;fa[x]=0;
while(l<r){
x=D[++l];
rep(i,x) if(da[i]!=fa[x]&&!p[da[i]]){
if(node[da[i]]>size/2) bz[x]=0;
D[++r]=da[i];bz[da[i]]=1;fa[da[i]]=x;
}
}l++;
while(l>1){
x=D[--l];if(bz[x]&&size-node[x]<=size/2) hea=x;
}
}
void sao(int x){
int i,l,r;
l=0;r=1;D[1]=x;
while(l<r){
x=D[++l];
if(de[x]>R) return;
if(de[x]>=L) ans=(ans>g[x])?ans:g[x];
d[2][++d[2][0]]=de[x];P[2][de[x]]=1;
t[2][de[x]]=T[2][de[x]]=(t[2][de[x]]>g[x])?t[2][de[x]]:g[x];
rep(i,x) if(da[i]!=fa[x]&&!p[da[i]]){
de[da[i]]=de[x]+1;lc[da[i]]=col[i];g[da[i]]=g[x];
if(lc[x]!=col[i]) g[da[i]]+=v[col[i]];
fa[da[i]]=x;D[++r]=da[i];
}
}
}
void ask(int x,int l,int r){
tot=INF;
while(l<=r){
if (r-(r&-r)>=l) tot=(t[x][r]>tot)?t[x][r]:tot,r-=r&-r;
else tot=(T[x][r]>tot)?T[x][r]:tot,r--;
}
}
void add(int x,int y,int z,int a){
T[x][y]=(T[x][y]>a)?T[x][y]:a;
for(;y<=n;y+=(y&-y)){
if(!P[x][y]) P[x][y]=1,d[x][++d[x][0]]=y;
t[x][y]=(t[x][y]>z)?t[x][y]:z;
}
}
void fill(int x){
int i;fo(i,1,d[x][0]) P[x][d[x][i]]=0,t[x][d[x][i]]=T[x][d[x][i]]=INF; d[x][0]=0;
}
void merge(int x,int y){
int i;
fo(i,1,d[y][0]){
add(x,d[y][i],t[y][d[y][i]],T[y][d[y][i]]);
P[y][d[y][i]]=0,t[y][d[y][i]]=T[y][d[y][i]]=INF;
}d[y][0]=0;
}
void divi(int x){
int i,j;bool bz;
gnode(x);hea=0;gheav(x,node[x]);x=hea;
if(ans>mx*node[x]) return;
p[x]=true;num=0;
rep(i,x) if(!p[da[i]]) son[++num].x=da[i],son[num].se=col[i];
sort(son+1,son+num+1,cmp);
fo(i,1,num){
bz=(i-1)?1:0;
if(i!=1&&son[i-1].se!=son[i].se) merge(0,1),bz=0;
de[son[i].x]=1,lc[son[i].x]=son[i].se,g[son[i].x]=v[son[i].se],fa[son[i].x]=x;
sao(son[i].x);
fo(j,1,d[2][0]){
l=(L-d[2][j]>1)?L-d[2][j]:1;r=R-d[2][j];
if(bz){
ask(1,l,r); tot+=-v[son[i].se]+t[2][d[2][j]];
ans=(ans>tot)?ans:tot;
}
ask(0,l,r);tot+=t[2][d[2][j]];
ans=(ans>tot)?ans:tot;
}
merge(1,2);
}
fill(0);if(son[num-1].se==son[num].se)fill(1);
rep(i,x) if(!p[da[i]]) divi(da[i]);
}
int main(){
freopen("journey.in","r",stdin);
freopen("journey.out","w",stdout);

scanf("%d%d%d%d",&n,&m,&L,&R);
fo(i,0,2) fo(j,0,n) t[i][j]=T[i][j]=INF;
ans=mx=INF;
fo(i,1,m) scanf("%d",&v[i]),mx=(mx>v[i])?mx:v[i];
fo(i,1,n-1){
scanf("%d%d%d",&x,&y,&z);
ins(x,y,z);
}
divi(1);
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息