「题解」洛谷 P8339 [AHOI2022] 钥匙
暴力:走 \(u\to v\) 路径时,遇到一个钥匙,将其压入对应颜色的栈,遇到一个宝箱,将栈顶的钥匙和其匹配,弹出这个钥匙。
特殊性质 A:考虑一个钥匙 \(x\) 及其对应的宝箱 \(y\),会对所有包含 \(x\to y\) 的路径(这里的包含要求和 \(x\to y\) 是一个方向),都会产生 \(1\) 的贡献。那么考虑在 \(dfn\times dfn\) 平面上,\((x,y)\) 代表的是 \(x\to y\) 对应的答案,每一个钥匙及其宝箱所对应的路径 \(x\to y\),根据 \(x,y\) 是否为祖先关系的不同,包含其的路径是子树补 \(\times\) 子树的矩形,或者子树 \(\times\) 子树补的矩形,或者子树 \(\times\) 子树的矩形。那么问题就变成了矩形 \(+1\),单点求值问题,用树状数组扫描线即可。
正解考虑借鉴上面两个做法的思想。
考虑一次暴力的贪心匹配的过程,一个钥匙和哪个宝箱匹配,和这个钥匙之前遇到的钥匙以及它们的匹配情况是无关的。所以对每个钥匙考虑,其贪心匹配过程中,往各个方向走,匹配到的宝箱集合是一定的。
暴力找出这个集合的过程就是,以这个钥匙 \(x\) 为根 dfs,维护一个栈,只存与根颜色相同的钥匙,然后匹配。直到有宝箱 \(y\) 和根代表的钥匙匹配成功了,那么 \(x\to y\) 会对所有包含 \(x\to y\) 的路径产生一个 \(1\) 的贡献,这里用特殊性质 A 的扫描线解决即可。
由于 dfs 的过程中只和同一颜色有关,所以把同一颜色的拉出来,在虚树上 dfs 找宝箱即可。
时间复杂度 \(\mathcal{O}(n\log n)\).
#include
#include
#include
#include
#include
#include
#define pb emplace_back
#define mp std::make_pair
#define fi first
#define se second
#define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<pii;
typedef pairpli;
typedef pairpll;
typedef vectorvi;
typedef vectorvll;
typedef vectorvpii;
templateT cmax(T &x, T y){return x=x>y?x:y;}
templateT cmin(T &x, T y){return x=x
T &read(T &r){
r=0;bool w=0;char ch=getchar();
while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar();
while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar();
return r=w?-r:r;
}
template
void read(T1 &x, T2& ...y){ read(x); read(y...); }
inline int lowbit(int x){return x&(-x);}
const int N=1000010;
int n,m,ct[N];
int t[N],c[N];
int ctc[N][3];
int fa[N],dep[N];
vi eg[N];
namespace ac{
int dfn[N],ofn[N],fi[N],ed[N],oft,dft,dep[N],fa[N][21],lg[N],siz[N];
int st[21][N],nowc;
int top,stk[N];
vi vec[N],et[N];
void dfs1(int x,int f){
fa[x][0]=f;dep[x]=dep[f]+1;siz[x]=1;
dfn[x]=++dft;fi[x]=++oft;ofn[oft]=x;
for(int i=1;i<=20;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
for(auto v:eg[x])if(v!=f){
dfs1(v,x);
siz[x]+=siz[v];
ed[v]=++oft;
ofn[oft]=x;
}
}
int LCA(int x,int y){
x=fi[x];y=fi[y];
int l=min(x,y),r=max(x,y);
int k=lg[r-l+1];
return dep[st[k][l]]dep[x])
y=fa[y][i];
return y;
}
int lct;
struct Line{
int l,r,h,v;
}li[N*10];
struct Que{
int x,y,i;
}q[N];
int ans[N];
int tree[N];
void modify(int x,int v){
for(;x<=n;x+=lowbit(x))tree[x]+=v;
}
void modify(int l,int r,int v){
modify(l,v);
if(rr1||l2>r2)return ;
// cout << l1 << ' ' << r1 << ' ' << l2 << ' ' << r2 << '\n';
li[++lct]={l2,r2,l1,1};
if(r1>1]+1;
for(int i=1;i<=20;i++)
for(int j=1;j+(1<1&&dep[t]1){
merge(stk[top],stk[top-1]);
po.pb(stk[top]);--top;
}
po.pb(1);
for(auto x:vec[o]){
if(t[x]==1){
dfs2(x,0,0,x);
}
}
for(auto x:po){
vi().swap(et[x]);
}
}
}
void Sao(){
sort(li+1,li+lct+1,[](const Line &x,const Line &y){return x.h