lxl这就是你带出来的oier
哈哈哈,出题人学数据结构疯了被爆标了。诶,我怎么在卡常,原来我也疯了哈哈哈。
:::info[说句闲话(并非一句)] long__long 大神打了 rk14,先给他磕了。
3 月 31 号看完了《末日三问》,然后:
我的 at 等级分。
北斗八星。。。神秘凸包状物。我对于自己开 Ynoi 的决定产生深深的疑惑。
这场月赛也是我后由乃时代唯一拟人的一把了,即使 T2 写前缀和优化建图奇异搞笑半天,T3 数学太差奇异搞笑半天。
赛后看到 T4 标签激动不已,在
这是我努力板刷 Ynoi 的成果!!!谁敢再说 Ynoi is useless!!!
搞什么,我会哭的。。。 :::
如果你疯了建议阅读这篇题解。
subtask0,1
遍历祖先动态规划即可。
subtask2
显然需要从 subtask2 的做法把线段树的 log 优化掉,也就是需要
对于修改位置的所在块,可以打 laz 标记,等查询时作为整块遍历到的时候暴力更新块内最大值。
每个点都会在
-
a_i > B
可以转化成
而此时所有的
而对于每个
所以现在需要一个数据结构维护权值区间的最大值,满足
单点最大值用堆即可。
这可以使用 p7811 的做法,块内暴力维护前缀最大值和后缀最大值,两两整块之间的最大值用 st 表维护,而 st 表的单点修改为
因为此时通过根号分治,一定满足
而对于修改逻辑就是个滑动窗口状物,显然你一定会有这个基础的。复杂度为
根号分治两种情况的复杂度都十分的好,所以我们就用出题人和做题人同时学疯数据结构才会写的做法通过了该题。
上代码,代码需要一定卡常。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
namespace IO {
const int MAXBUF = 1 << 20;
char buf[MAXBUF], *p1 = buf, *p2 = buf;
char outbuf[MAXBUF], *outp = outbuf;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, MAXBUF, stdin), p1 == p2) ? EOF : *p1++)
template<class T>
inline void read(T &x) {
x = 0; int f = 1; char ch = gc();
while (!isdigit(ch)) { if (ch == '-') f = -1; ch = gc(); }
while (isdigit(ch)) { x = x * 10 + (ch - '0'); ch = gc(); }
x *= f;
}
template<class T>
inline void write(T x) {
if (x < 0) { *outp++ = '-'; x = -x; }
static int sta[35]; int top = 0;
do { sta[top++] = x % 10; x /= 10; } while (x);
while (top) *outp++ = sta[--top] + '0';
}
inline void flush() {
fwrite(outbuf, 1, outp - outbuf, stdout);
outp = outbuf;
}
}
using namespace IO;
const int N=3e5+5,B=200;
const ll inf=0x3f3f3f3f3f3f3f3f;
struct st{
int to,nxt;
}edge[N<<1];
int head[N],cnt,a[N],dep[N],n,num,len,L[N/B+5],R[N/B+5],belong[N],tot[N],LG[N];
priority_queue < ll > q[N],del[N];
bool laz[B+5][N/B+5];
ll dp[N],ans,w[B+5][N],mx[B+5][N/B+5],st[N/B+5][15],pre[N],suf[N],b[N];
inline void add(int x,int y){
edge[++cnt]={y,head[x]},head[x]=cnt;
}
inline void change(int p,int x,ll k){
w[p][x]=k;
laz[p][belong[x]]=1;
}
inline void solve(int p,int bel){
mx[p][bel]=-inf;
for (int i=L[bel];i<=R[bel];i++) mx[p][bel]=max(mx[p][bel],w[p][i]);
laz[p][bel]=0;
}
inline ll gbc(int p,int x,int y){
if (belong[x]==belong[y]){
ll ret=-inf;
for (int i=x;i<=y;i++) ret=max(ret,w[p][i]);
return ret;
}
int bel_x=belong[x],bel_y=belong[y];ll ret=-inf;
for (int i=x;i<=R[bel_x];i++) ret=max(ret,w[p][i]);
for (int i=L[bel_y];i<=y;i++) ret=max(ret,w[p][i]);
for (int i=bel_x+1;i<bel_y;i++){
if (laz[p][i]) solve(p,i);
ret=max(ret,mx[p][i]);
}
return ret;
}
inline ll get(int x){
if (q[x].size()==del[x].size()) return -inf;
while (del[x].size()&&q[x].top()==del[x].top()) q[x].pop(),del[x].pop();
return q[x].top();
}
inline void ch(int x){
ll val=get(x);
int bel=belong[x];
if (b[x]==val) return ;
b[x]=val;
pre[L[bel]]=b[L[bel]];
suf[R[bel]]=b[R[bel]];
for (int i=L[bel]+1;i<=R[bel];i++) pre[i]=max(pre[i-1],b[i]);
for (int i=R[bel]-1;i>=L[bel];i--) suf[i]=max(suf[i+1],b[i]);
ll mx=pre[R[bel]];st[bel][0]=mx;
for (int k=1;k<=10;k++){
for (int i=max(bel-(1<<k)+1,1);i<=min(bel,num-(1<<k)+1);i++) st[i][k]=max(st[i][k-1],st[i+(1<<(k-1))][k-1]);
}
}
inline ll gbc_st(int x,int y){
if (x>y) return -inf;
int Lg=LG[y-x+1];
return max(st[x][Lg],st[y-(1<<Lg)+1][Lg]);
}
inline ll gbc(int x,int y){
if (belong[x]==belong[y]){
ll ret=-inf;
for (int i=x;i<=y;i++) ret=max(ret,b[i]);
return ret;
}
ll ret=-inf;
ret=max(max(ret,max(suf[x],pre[y])),gbc_st(belong[x]+1,belong[y]-1));
return ret;
}
inline void dfs(int x,int fa){
tot[dep[x]=dep[fa]+1]=x;
if (x!=1){
dp[x]=-inf;
if (a[x]<=B) dp[x]=gbc(a[x],max(1,dep[x]-len),dep[x]-1);
else{
for (int k=0;k*a[x]<=3e5;k++){
int LL=max(1,k*a[x]),RR=min((k+1)*a[x]-1,300000);
dp[x]=max(dp[x],gbc(LL,RR)-k*a[x]);
}
}
ans=max(ans,dp[x]);
}
for (int i=1;i<=B;i++) change(i,dep[x],dp[x]+a[x]%i);
int fx=dep[x]-len<=0?0:tot[dep[x]-len];
if (fx) del[a[fx]].push(dp[fx]+a[fx]),ch(a[fx]);
q[a[x]].push(dp[x]+a[x]),ch(a[x]);
for (int i=head[x];i;i=edge[i].nxt){
int v=edge[i].to;
if (v==fa) continue;
dfs(v,x);
}
if (fx) q[a[fx]].push(dp[fx]+a[fx]),ch(a[fx]);
del[a[x]].push(dp[x]+a[x]),ch(a[x]);
}
inline void build_block(){
num=300000/B+(bool)(300000%B);
for (int i=1;i<=num;i++){
L[i]=(i-1)*B+1;
R[i]=i*B;
}
R[num]=300000;
for (int i=1;i<=num;i++){
for (int j=L[i];j<=R[i];j++) belong[j]=i,b[j]=pre[j]=suf[j]=-inf;
for (int j=0;j<=10;j++) st[i][j]=-inf;
}
for (int p=1;p<=B;p++){
for (int i=1;i<=300000;i++) w[p][i]=-inf;
for (int i=1;i<=num;i++) mx[p][i]=-inf;
}
}
struct BL{
int f[N];
inline void dfs_baoli(int x,int fa){
int v=fa;
for (int i=1;i<=len;i++){
if (!v) break;
dp[x]=max(dp[x],dp[v]+a[v]%a[x]);
v=f[v];
}
ans=max(ans,dp[x]);
f[x]=fa;
for (int i=head[x];i;i=edge[i].nxt){
int v=edge[i].to;
if (v==fa) continue;
dfs_baoli(v,x);
}
}
}baoli;
signed main(){
read(n); read(len);
for (int i=2;i<=3e5;i++) LG[i]=LG[i>>1]+1;
for (int i=1;i<=n;i++) read(a[i]);
for (int i=1;i<n;i++){
int x,y; read(x); read(y);
add(x,y),add(y,x);
}
if (len<=2000){
baoli.dfs_baoli(1,0);
write(ans); *outp++ = '\n'; flush();
return 0;
}
build_block();
dfs(1,0);
write(ans); *outp++ = '\n'; flush();
return 0;
}