题解:P10866 [HBCPC2024] Colorful Tree
在 S 组模拟赛的 T3 做到了这一题,分享一种树剖+set 的做法。
思路
一个点只会从白变黑一次,考虑求出每次操作会有哪些白点变黑。既然是树上路径问题就考虑树剖,维护每条重链上剩余白点的集合,用 set 按每个点的深度排序(当然你按 dfn 排也行),则每次操作会删掉一段连续的白点,暴力删就行。
然后路径修改就变成了单点修改,正着操作时黑点只增不删,倒着操作时白点只增不删,于是正反跑两次,用并查集维护联通块内直径的端点就可以分别算出黑点和白点贡献的答案。这部分其他题解都讲得很清楚,这里就不细讲了。
时间复杂度 \(O(q\log^2 n+n\log n+n\alpha(n))\)。
代码
代码是赛时写的,比较丑陋。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int N=2e5+5,P=1e9+7,inf=2e9;
int rd()
{
int fl=1,x=0;char c=getchar();
while(c>'9' || c<'0')
{
if(c=='-')
fl=-1;
c=getchar();
}
while(c<='9' && c>='0')
{
x=x*10+c-'0';
c=getchar();
}
return x*fl;
}
void wt(int x,char c='~')
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
wt(x/10);
putchar(x%10+'0');
if(c!='~')
putchar(c);
}
int n,q,fa[N],dep[N],ch[N],sz[N],top[N],ord[N],dfn[N],tot,flag[N],up[N],ans[N];
pii mn[N][20],p[N];
vector<int> e[N],del[N];
set<pii> s[N];
void dfs1(int x)
{
sz[x]=1;ch[x]=0;
for(int y:e[x])
if(y!=fa[x])
{
fa[y]=x;
dep[y]=dep[x]+1;
dfs1(y);
sz[x]+=sz[y];
if(sz[y]>sz[ch[x]])
ch[x]=y;
}
}
void dfs2(int x)
{
ord[++tot]=x;
dfn[x]=tot;
s[top[x]].insert({dep[x],x});
if(!ch[x])
return;
top[ch[x]]=top[x];
dfs2(ch[x]);
for(int y:e[x])
if(y!=fa[x]&&y!=ch[x])
{
top[y]=y;
dfs2(y);
}
}
int getmin(int l,int r)
{
int lg=__lg(r-l+1);
return min(mn[l][lg],mn[r-(1<<lg)+1][lg]).second;
}
int lca(int x,int y)
{
if(x==y)
return x;
if(dfn[x]>dfn[y])
swap(x,y);
return fa[getmin(dfn[x]+1,dfn[y])];
}
int getdis(int x,int y)
{
return dep[x]+dep[y]-2*dep[lca(x,y)]+1;
}
void update(vector<int> &d,int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
while(s[top[x]].size())
{
if(s[top[x]].begin()->first>dep[x])
break;
d.push_back(s[top[x]].begin()->second);
s[top[x]].erase(s[top[x]].begin());
}
x=fa[top[x]];
}
if(dep[x]<dep[y])
swap(x,y);
while(s[top[x]].size())
{
auto it=s[top[x]].lower_bound({dep[y],y});
if(it==s[top[x]].end()||it->first>dep[x])
break;
d.push_back(it->second);
s[top[x]].erase(it);
}
}
int getfa(int x)
{
if(x!=up[x])
up[x]=getfa(up[x]);
return up[x];
}
void merge(int x,int y)
{
x=getfa(x);y=getfa(y);
if(x==y)
return;
pii nxt=p[x];
int v0=getdis(nxt.first,nxt.second);
int v=getdis(p[y].first,p[y].second);
if(v>v0)
{
v0=v;
nxt=p[y];
}
v=getdis(p[x].first,p[y].first);
if(v>v0)
{
v0=v;
nxt={p[x].first,p[y].first};
}
v=getdis(p[x].second,p[y].first);
if(v>v0)
{
v0=v;
nxt={p[x].second,p[y].first};
}
v=getdis(p[x].first,p[y].second);
if(v>v0)
{
v0=v;
nxt={p[x].first,p[y].second};
}
v=getdis(p[x].second,p[y].second);
if(v>v0)
{
v0=v;
nxt={p[x].second,p[y].second};
}
up[y]=x;
p[x]=nxt;
}
void add(int x)
{
flag[x]=1;
up[x]=x;
p[x]={x,x};
for(int y:e[x])
if(flag[y])
merge(x,y);
}
void solve()
{
n=rd();q=rd();
tot=0;
for(int i=1;i<=max(n,q);i++)
flag[i]=0,e[i].clear(),del[i].clear(),s[i].clear();
for(int i=1;i<n;i++)
{
int x,y;
x=rd();y=rd();
e[x].push_back(y);
e[y].push_back(x);
}
dfs1(1);
top[1]=1;
dfs2(1);
for(int i=1;i<=n;i++)
mn[i][0]={dep[ord[i]],ord[i]};
for(int j=1;j<=18;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
int now=0;
for(int i=1;i<=q;i++)
{
int x,y;
x=rd();y=rd();
update(del[i],x,y);
for(int x:del[i])
{
add(x);
now=max(now,getdis(p[getfa(x)].first,p[getfa(x)].second));
}
ans[i]=now;
}
vector<int> res;
for(int i=1;i<=n;i++)
{
if(!flag[i])
res.push_back(i);
flag[i]=0;
}
now=0;
for(int x:res)
add(x),now=max(now,getdis(p[getfa(x)].first,p[getfa(x)].second));
ans[q]=max(ans[q],now);
for(int i=q;i>1;i--)
{
for(int x:del[i])
{
add(x);
now=max(now,getdis(p[getfa(x)].first,p[getfa(x)].second));
}
ans[i-1]=max(ans[i-1],now);
}
for(int i=1;i<=q;i++)
wt(ans[i],'\n');
return;
}
signed main()
{
int T=rd();
while(T--)
solve();
return 0;
}

浙公网安备 33010602011771号