题解:P12653 [KOI 2024 Round 2] 分数竞赛
Solution
伟大的安徽字典序队长 FS_NEO 指出:
考虑固定起点和终点怎么计算答案。也就是做线性序列。
设
那么最终的得分是:
看到树上路径统计问题,想到点分治。
设分治中心是
所以
以
对于蓝色的路径(从
那么前缀最小值个数呢?首先考虑蓝色区域的前缀最小值个数,它们是不受影响的。容易使用树上倍增求出每个位置之后的第一个比他低的谷,如图所示:
对于红色部分,如果一个位置是拼接之后的前缀最小值,那么一定是原序列的前缀最小值,并且满足
说起来容易,代码非常冗杂,而且有点卡常。
#include<bits/stdc++.h>
#define ll long long
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=3e5+10;const ll INF=1e12;
int n,dep[MAXN],FA[MAXN],fa[MAXN][20];
vector<pair<int,int>> G[MAXN];
ll pre[MAXN],mn[MAXN],mx[MAXN],ans1[MAXN],ans2[MAXN];
int sze[MAXN],cut[MAXN],mxs[MAXN];
inline void dfs1(const int u,const int f) {
sze[u]=1,mxs[u]=0;
for(auto pr:G[u]) {
int v=pr.first,w=pr.second;
if(v==f||cut[v]) continue ;
dfs1(v,u),mxs[u]=max(mxs[u],sze[v]),sze[u]+=sze[v];
}
return ;
}
vector<int> bel[MAXN];
inline int find_core(const int u,const int f,const int al) {
if(max(mxs[u],al-sze[u])<=al/2) return u;
for(auto pr:G[u]) {
int v=pr.first,w=pr.second;
if(v==f||cut[v]) continue ;
int tans=find_core(v,u,al);
if(tans!=-1) return tans;
}
return -1;
}
inline void dfs2(const int u,const int f,const int LIM) {
mx[u]=mn[u]=pre[u],sze[u]=1,FA[u]=f;
if(f) mx[u]=max(mx[u],mx[f]),mn[u]=min(mn[u],mn[f]);
if(f) {
if(pre[f]>pre[u]) fa[u][0]=f,dep[u]=dep[f]+1;
else if(pre[u]>=mx[f]) fa[u][0]=u,dep[u]=0;
else {
int pos=f;
roff(i,LIM,0) if(pre[fa[pos][i]]<=pre[u]) pos=fa[pos][i];
pos=fa[pos][0],fa[u][0]=pos,dep[u]=dep[pos]+1;
}
ffor(i,1,LIM) fa[u][i]=fa[fa[u][i-1]][i-1];
}
else ffor(i,0,LIM) fa[u][i]=0;
for(auto pr:G[u]) {
int v=pr.first,w=pr.second;
if(v==f||cut[v]) continue ;
pre[v]=pre[u]+w,dfs2(v,u,LIM),sze[u]+=sze[v];
}
return ;
}
struct INFO {ll sze,val;int cnt;};
namespace SGT {
const int MAXM=1.5e7+10;
int tot=0;
struct Node {int ls,rs;ll sze,val;int cnt;}t[MAXM];
inline INFO operator +(const INFO A,const INFO B) {return {A.sze+B.sze,A.val+B.val,A.cnt+B.cnt};}
inline void init(void) {return tot=0,void();}
inline int get_node(void) {return ++tot,t[tot]={0,0,0,0,0},tot;}
inline void update(int &u,const ll l,const ll r,const ll x,const int dsze,const ll dval,const int dcnt) {
if(!u) u=get_node();
t[u].sze+=dsze,t[u].val+=dval,t[u].cnt+=dcnt;
if(l!=r) {
ll mid=l+(r-l)/2;
if(x<=mid) update(t[u].ls,l,mid,x,dsze,dval,dcnt);
else update(t[u].rs,mid+1,r,x,dsze,dval,dcnt);
}
return ;
}
inline INFO query(const int u,const ll l,const ll r,const ll x,const ll y) {
if(!u) return {0,0,0};
if(x<=l&&r<=y) return {t[u].sze,t[u].val,t[u].cnt};
INFO ans={0,0,0};
ll mid=l+(r-l)/2;
if(x<=mid) ans=ans+query(t[u].ls,l,mid,x,y);
if(y>mid) ans=ans+query(t[u].rs,mid+1,r,x,y);
return ans;
}
};
inline void mark(const int u,const int f,const int anc) {
bel[anc].push_back(u);
for(auto pr:G[u]) {
int v=pr.first,w=pr.second;
if(v==f||cut[v]) continue ;
mark(v,u,anc);
}
return ;
}
inline void solve(int u) {
dfs1(u,0);
if(sze[u]==1) return cut[u]=1,void();
int lim=__lg(sze[u]/2);
u=find_core(u,0,sze[u]);
dep[u]=pre[u]=mn[u]=mx[u]=0,dfs2(u,0,lim);
bel[u].clear(),bel[u].push_back(u);
vector<int> T;
for(auto pr:G[u]) {
int v=pr.first;
if(cut[v]) continue ;
T.push_back(v);
}
bel[u].clear(),bel[u].push_back(u);
for(auto v:T) bel[v].clear(),mark(v,u,v);
vector<int> S=T; S.push_back(u);
SGT::init();
int rt=0;ll ts=0;
for(auto id:S) {
for(auto v:bel[id]) {
ll sum1=pre[v],mn1=pre[v]-mx[v];
INFO L;
if(rt) L={SGT::t[rt].sze,SGT::t[rt].val,SGT::t[rt].cnt};
else L={0,0,0};
INFO R=SGT::query(rt,-INF,INF,mn1-sum1,INF);
L.sze=L.sze-R.sze,L.val=L.val-R.val,L.cnt=L.cnt-R.cnt;
ans1[v]+=(sum1*(L.cnt+R.cnt)+ts)-(sum1*L.cnt+L.val+R.cnt*mn1);
ans2[v]+=1ll*dep[v]*(L.cnt+R.cnt)+L.sze;
}
for(auto v:bel[id]) {
ll dsze=0,dval=mn[v],dcnt=1;
if(v!=u&&pre[v]<mn[FA[v]]) dsze=sze[v];
SGT::update(rt,-INF,INF,mn[v],dsze,dval,dcnt),ts+=pre[v];
}
}
SGT::init(),rt=0,ts=0,reverse(S.begin(),S.end());
for(auto id:S) {
for(auto v:bel[id]) {
ll sum1=pre[v],mn1=pre[v]-mx[v];
INFO L;
if(rt) L={SGT::t[rt].sze,SGT::t[rt].val,SGT::t[rt].cnt};
else L={0,0,0};
INFO R=SGT::query(rt,-INF,INF,mn1-sum1,INF);
L.sze=L.sze-R.sze,L.val=L.val-R.val,L.cnt=L.cnt-R.cnt;
ans1[v]+=(sum1*(L.cnt+R.cnt)+ts)-(sum1*L.cnt+L.val+R.cnt*mn1);
ans2[v]+=1ll*dep[v]*(L.cnt+R.cnt)+L.sze;
}
for(auto v:bel[id]) {
ll dsze=0,dval=mn[v],dcnt=1;
if(v!=u&&pre[v]<mn[FA[v]]) dsze=sze[v];
SGT::update(rt,-INF,INF,mn[v],dsze,dval,dcnt),ts+=pre[v];
}
}
cut[u]=1;
for(auto v:T) solve(v);
return ;
}
int main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n;
ffor(i,1,n-1) {
int u,v,w;
cin>>u>>v>>w;
G[u].push_back({v,w}),G[v].push_back({u,w});
}
solve(1);
cout<<1<<'\n';
ffor(i,1,n) cout<<ans1[i]<<' '; cout<<'\n';
ffor(i,1,n) cout<<ans2[i]<<' '; cout<<'\n';
return 0;
}