题面
https://www.lydsy.com/JudgeOnline/problem.php?id=4860
题解
点分治
设当前重心为v
假设已经把所有边按照出发点第一关键字, 颜色第二关键字排序
对于当前的v 我们顺次考虑他的出边
设当前出边(v,nw) 颜色 col
我们枚举nw的出边
对于一条nw的出边而言, 分为两种情况
1. 颜色与col相同 用线段树维护深度及对应的最值,查询到最大值即可 (v,nw)没有贡献
2. 颜色与col不同 用另一棵线段树维护深度以及与(当前节点的连向其父节点的边的颜色)不同的(连向子节点的边)所对应的子节点对应的子树之内的最值 加上col的权值
向上的时候 将线段树合并
Code
1 #include <cstdio>
2 #include <cctype>
3 #include <algorithm>
4 const int maxn=400010,inf=2000000010;
5 int ans,n,x,y,z,i,m,l,r,c[maxn*3],cnt;
6 inline int max(int a,int b){
7 return a>b?a:b;
8 }
9 inline void up(int&a,const int&b){
10 if(a<b)a=b;
11 }
12 inline int getint(){
13 char c=getchar();
14 int x=0,neg=1;
15 while(!isdigit(c)){
16 if(c=='-')neg=-1;
17 c=getchar();
18 }
19 while(isdigit(c)){
20 x=x*10+c-48;
21 c=getchar();
22 }
23 return x*neg;
24 }
25 struct edge{
26 int from,to,color;
27 }e[maxn<<1];
28 struct data{
29 int dep,sum;
30 };
31 struct node{
32 int v,lc,rc;
33 }a[maxn*5];
34 int merge(int x,int y){
35 if(!x || !y )return x|y;
36 a[x].lc=merge(a[x].lc,a[y].lc);
37 a[x].rc=merge(a[x].rc,a[y].rc);
38 up(a[x].v,a[y].v);
39 return x;
40 }
41 void add(int&i,int rl,int rr,int x,int v){
42 if(!i)a[i=++cnt]=(node){v,0,0};
43 else up(a[i].v,v);
44 if(rl<rr){
45 int m=(rl+rr)>>1;
46 if(x>m)add(a[i].rc,m+1,rr,x,v);
47 else add(a[i].lc,rl,m,x,v);
48 }
49 }
50 int query(int i,int rl,int rr,int l,int r){
51 if(!i)return -inf;
52 if(rl==l && rr==r)return a[i].v;
53 int m=(rl+rr)>>1;
54 if(l>m)return query(a[i].rc,m+1,rr,l,r);
55 else if(r<=m)return query(a[i].lc,rl,m,l,r);
56 else return max(query(a[i].lc,rl,m,l,m),query(a[i].rc,m+1,rr,m+1,r));
57 }
58 struct tree{
59 int xb,h[maxn],n,size[maxn],f[maxn],rt,sum,dep[maxn],ll,ss[maxn];
60 bool b[maxn];
61 data w[maxn];
62 void addedge(int x,int y,int z){
63 e[++xb]=(edge){y,x,z};
64 e[++xb]=(edge){x,y,z};
65 }
66 void dfs(int x,int fa){
67 size[x]=f[x]=1;
68 for(int i=h[x];i<h[x+1];++i){
69 int y=e[i].to;
70 if(y!=fa && !b[y]){
71 dfs(y,x);
72 size[x]+=size[y];
73 up(f[x],size[y]);
74 }
75 }
76 up(f[x],sum-size[x]);
77 if(f[rt]>f[x])rt=x;
78 }
79 void got(int x,int fa,int dep,int color,int sum){
80 for(int y,i=h[x];i<h[x+1];++i){
81 y=e[i].to;
82 if(y!=fa && !b[y]){
83 if(e[i].color==color)w[++ll]=(data){dep+1,sum};
84 else w[++ll]=(data){dep+1,sum+c[e[i].color]};
85 got(e[i].to,x,dep+1,e[i].color,w[ll].sum);
86 }
87 }
88 }
89 void solve(int x){
90 b[x]=1;
91 int i,rt1=0,rt2=cnt=0,j;
92 for(i=h[x];i<h[x+1];++i){
93 if(i>h[x] && e[i].color>e[i-1].color)rt1=merge(rt1,rt2),rt2=0;
94 if(!b[e[i].to]){
95 w[ll=1]=(data){1,c[e[i].color]};
96 got(e[i].to,x,1,e[i].color,c[e[i].color]);
97 ss[i]=ll;
98 for(j=1;j<=ll;++j)if(w[j].dep<=r){
99 if(w[j].dep>=l)up(ans,w[j].sum);
100 if(w[j].dep<r){
101 up(ans,query(rt1,1,n,max(1,l-w[j].dep),r-w[j].dep)+w[j].sum);
102 up(ans,query(rt2,1,n,max(1,l-w[j].dep),r-w[j].dep)-c[e[i].color]+w[j].sum);
103 }
104 }
105 for(j=1;j<=ll;++j)if(w[j].dep<=r)add(rt2,1,n,w[j].dep,w[j].sum);
106 }
107 }
108 for(i=h[x];i<h[x+1];++i)
109 if(!b[e[i].to]){
110 sum=ss[i];
111 rt=0;
112 dfs(e[i].to,x);
113 solve(rt);
114 }
115 }
116 }t;
117 bool cmp(const edge&a,const edge&b){
118 return a.from==b.from?a.color<b.color:a.from<b.from;
119 }
120 int main(){
121 //freopen("input","r",stdin);
122 a[0].v=-inf;
123 t.n=n=getint();
124 m=getint();
125 l=getint();
126 r=getint();
127 for(i=1;i<=m;++i)c[i]=getint();
128 for(i=1;i<n;++i){
129 x=getint();
130 y=getint();
131 z=getint();
132 t.addedge(x,y,z);
133 }
134 std::sort(e+1,e+((n-1)*2)+1,cmp);
135 for(i=1;i<=((n-1)<<1);++i)
136 if(!t.h[e[i].from])t.h[e[i].from]=i;
137 t.h[n+1]=(n-1)<<1|1;
138 t.f[t.rt=0]=inf;
139 t.sum=n;
140 ans=-inf;
141 t.dfs(1,0);
142 t.solve(t.rt);
143 printf("%d\n",ans);
144 }
Review
一开始以为是树形dp 后来发现那是错的
还可以用单调队列过 好像更简单
来源:oschina
链接:https://my.oschina.net/u/4339058/blog/3896496