CF1137F Matches Are Not a Child's Play 题解
题目链接
题目解法
参考 abruce 的非 \(lct\) 的做法
\(compare\) 操作是搞笑的,可以转化成求 \(u,v\) 的 \(when\) 操作
一个结论是编号最大的点一定是最晚删的,不妨令编号最大的点为根,则删除顺序一定是从下往上删的
先考虑原树上单个点 \(u\) 的 \(when\) 怎么求
令 \(mx_u\) 为 \(u\) 子树中编号最大的点,\(to_u\) 表示 \(u\) 子树中编号最大点的位置
则满足 \(mx_v<mx_u\) 的 \(v\) 一定比 \(u\) 先选到
考虑 \(mx_v=mx_u\) 的 \(v\) 有多少个比 \(u\) 先选
画个图不难发现,\(u\) 子树中只会剩下 \(u\) 到 \(to_u\) 的一条链,那么从下往上删即可
所以单个点 \(u\) 的 \(when\) 即为 \(\sum [mx_v<mx_u]+dist(u,to_u)\)
操作 \(up\) 相当于把根换成 \(u\)
考虑如何维护出新的 \(mx\) 和 \(to\)
不难发现,只有原根到新根的路径上的点的 \(mx\) 会有影响,且 \(mx\) 都变成原根的编号(除了 \(mx_u=\max+1\))
而且更好的是,这些点的 \(to\) 都为原根(且换根时不会影响除了路径上的其他点的 \(to\))
这就好做了,我们现在只需要维护区间改颜色,和查颜色 \(<x\) 的数的个数(用树剖转化成区间操作)
这里有一个很常用的维护颜色段的 \(trick\):颜色段均摊
即用 \(set\) 维护每个颜色段,每次修改暴力删和加即可
因为加入的段是 \(O(n+q\log n)\) 的,而每个段只会删除一次,所以复杂度是 \(O(n\log n+q\log^2 n)\) 的
\(<x\) 的数的个数直接套个树状数组即可
时间复杂度 \(O(n\log n+q\log^2 n)\)
#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
template<typename T> void read(T &FF){
FF=0;int RR=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
FF*=RR;
}
const int N=400010;
vector<int> G[N];
int fa[N],siz[N],son[N],dep[N],top[N],dfn[N],rv[N],clk;
int mx[N];
int st[N][20],lg[N],cnt,fir[N];
void dfs1(int u){
siz[u]=1,dep[u]=dep[fa[u]]+1,mx[u]=u;
st[++cnt][0]=dep[u],fir[u]=cnt;
for(int v:G[u]) if(v!=fa[u]){
fa[v]=u,dfs1(v),st[++cnt][0]=dep[u];
chkmax(mx[u],mx[v]);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t,dfn[u]=++clk,rv[clk]=u;
if(!son[u]) return;
dfs2(son[u],t);
for(int v:G[u]) if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
#define lowbit(x) x&-x
struct fenwick{
int n,tr[N];
void add(int x,int v){ for(;x<=n;x+=lowbit(x)) tr[x]+=v;}
int ask(int x){ int res=0;for(;x;x-=lowbit(x)) res+=tr[x];return res;}
}tr;
struct ds{
int l,r,v;
bool operator <(const ds &o)const{ return l<o.l;}
};
set<ds> se;
int key[N];
auto split(int p){
auto it=se.lower_bound({p,-1,-1});
if(it!=se.end()&&it->l==p) return it;
it--;
if(it->r<p) return se.end();
auto [l,r,v]=*it;
se.erase(it),se.insert({l,p-1,v});
return se.insert({p,r,v}).first;
}
void assign(int l,int r,int v){
auto itr=split(r+1),itl=split(l);
for(auto it=itl;it!=itr;it++) tr.add(it->v,-(it->r-it->l+1));
se.erase(itl,itr);
se.insert({l,r,v}),tr.add(v,r-l+1);
}
void mdf_sgl(int u,int submx){ assign(dfn[u],dfn[u],submx);}
void mdf_path(int u,int v,int submx){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
assign(dfn[top[u]],dfn[u],submx),u=fa[top[u]];
}
if(dfn[u]>dfn[v]) swap(u,v);
assign(dfn[u],dfn[v],submx);
}
int lcadep(int x,int y){
x=fir[x],y=fir[y];
if(x>y) swap(x,y);
int k=lg[y-x+1];
return min(st[x][k],st[y-(1<<k)+1][k]);
}
int dist(int x,int y){ return dep[x]+dep[y]-lcadep(x,y)*2+1;}
int query(int u){
auto it=se.lower_bound({dfn[u]+1,-1,-1});it=prev(it);
return tr.ask(it->v-1)+dist(u,key[it->v]);
}
int main(){
int n,q;read(n),read(q);tr.n=n+q;
F(i,1,n-1){
int x,y;read(x),read(y);
G[x].pb(y),G[y].pb(x);
}
dfs1(n),dfs2(n,n);
F(i,2,cnt) lg[i]=lg[i>>1]+1;
F(j,1,18) F(i,1,cnt-(1<<j)+1) st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
int rt=n;
F(i,1,n) key[i]=i;
F(i,1,n) tr.add(mx[i],1),se.insert({dfn[i],dfn[i],mx[i]});
while(q--){
char op[10];scanf("%s",op);
int u,v;read(u);
if(op[0]=='u'){
mdf_path(rt,u,n);
key[++n]=u,mdf_sgl(u,n),rt=u;
}
else if(op[0]=='w') printf("%d\n",query(u));
else{
read(v);
if(query(u)<query(v)) printf("%d\n",u);else printf("%d\n",v);
}
}
return 0;
}

浙公网安备 33010602011771号