题解:P11340 [COI 2019] TENIS
LastKismet · · 题解
Sol
为什么都在找性质啊,这个不是暴力维护一下就行了吗。
前情提要:模拟赛 T3 放这个一眼秒了然后挂大分。
如果我们把图建出来的话,显然只要满足缩点之后查询的点入度为
考虑以第一条链为基准,视其为一棵 DFS 生成树,然后对另外两条链,不难发现有用的其实只有链上相邻两点的连边,把这些新的边视作非树边直接连到第一条链生成的链状生成树上去。后文的“链”无特殊说明均指作为基准的第一条链。
先不考虑修改,考虑一个点所在连通分量缩点后入度为零的充要条件,那么只要这个点与链头在一个 SCC 即可,更一般的,要求链上链头到当前点的每个点(不考虑链头)均满足后缀
维护这个的话,只需要维护最前面一个后缀
由于是一条链,可以在线段树上维护区间最小
void change(int k,int v,int x=1,int l=2,int r=n){
if(k<l)return;
if(l==r)return dat[x]=v,res[x]=(dat[x]>=l?l:n+1),void();
int m=l+r>>1;
if(k<=m)change(k,v,x<<1,l,m);
else change(k,v,x<<1|1,m+1,r);
dat[x]=min(dat[x<<1],dat[x<<1|1]);
res[x]=res[x<<1];
if(dat[x<<1|1]<res[x])res[x]=res[x<<1|1];
}
上面代码是修改一个点的 res[1](若无赋值为
考虑修改,不难发现,我们每次只会断开相应链上与两个互换点相连的不超过
特殊地,如果改的是基准链,那么虽然不用断边或者连边,但是由于
易错点:一定要把所有要更新的点更新完!可能有重边所以不要用 set 存图!!!
所以为什么这种奶龙题赛时会挂挂挂呢。QAQ
Code
const int N=1e5+5,P=4;
int n,q;
int a[N];
int l[P][N],rk[P][N];
int low[N];
int dat[N<<2],res[N<<2];
void change(int k,int v,int x=1,int l=2,int r=n){
if(k<l)return;
if(l==r)return dat[x]=v,res[x]=(dat[x]>=l?l:n+1),void();
int m=l+r>>1;
if(k<=m)change(k,v,x<<1,l,m);
else change(k,v,x<<1|1,m+1,r);
dat[x]=min(dat[x<<1],dat[x<<1|1]);
res[x]=res[x<<1];
if(dat[x<<1|1]<res[x])res[x]=res[x<<1|1];
}
multiset<int> g[N];
inline void Main(){
cin>>n>>q;
rep(p,1,3){
rep(i,1,n)cin>>l[p][i],rk[p][l[p][i]]=i;
if(p==1)rep(i,1,n)low[i]=rk[1][i];
if(p>1){
repl(i,1,n){
int x=l[p][i],y=l[p][i+1];
chmin(low[x],rk[1][y]);
g[x].insert(y);
}
}
}
rep(i,1,n)change(rk[1][i],low[i]);
rep(i,1,q){
int op;cin>>op;
if(op==1){
int x;cin>>x;
put(res[1]>rk[1][x]?"DA":"NE");
}else{
int p,a,b;cin>>p>>a>>b;
if(rk[p][a]>rk[p][b])swap(a,b);
if(p==1){
swap(l[1][rk[1][a]],l[1][rk[1][b]]);
swap(rk[1][a],rk[1][b]);
swap(a,b);
low[a]=rk[1][a];
for(auto k:g[a])chmin(low[a],rk[1][k]);
change(rk[1][a],low[a]);
low[b]=rk[1][b];
for(auto k:g[b])chmin(low[b],rk[1][k]);
change(rk[1][b],low[b]);
rep(p,2,3){
int z;
if(rk[p][a]>1){
z=l[p][rk[p][a]-1];
low[z]=rk[1][z];
for(auto k:g[z])chmin(low[z],rk[1][k]);
change(rk[1][z],low[z]);
}
if(rk[p][b]>1){
z=l[p][rk[p][b]-1];
low[z]=rk[1][z];
for(auto k:g[z])chmin(low[z],rk[1][k]);
change(rk[1][z],low[z]);
}
}
}else{
int z;
if(rk[p][a]>1){
z=l[p][rk[p][a]-1];
g[z].erase(g[z].lower_bound(a));
}
if(rk[p][a]<n){
z=l[p][rk[p][a]+1];
g[a].erase(g[a].lower_bound(z));
}
if(rk[p][b]>1&&l[p][rk[p][b]-1]!=a){
z=l[p][rk[p][b]-1];
g[z].erase(g[z].lower_bound(b));
}
if(rk[p][b]<n){
z=l[p][rk[p][b]+1];
g[b].erase(g[b].lower_bound(z));
}
swap(l[p][rk[p][a]],l[p][rk[p][b]]);
swap(rk[p][a],rk[p][b]);
swap(a,b);
if(rk[p][a]>1){
z=l[p][rk[p][a]-1];
g[z].insert(a);
low[z]=rk[1][z];
for(auto k:g[z])chmin(low[z],rk[1][k]);
change(rk[1][z],low[z]);
}
if(rk[p][a]<n){
z=l[p][rk[p][a]+1];
g[a].insert(z);
}
if(rk[p][b]>1&&l[p][rk[p][b]-1]!=a){
z=l[p][rk[p][b]-1];
g[z].insert(b);
low[z]=rk[1][z];
for(auto k:g[z])chmin(low[z],rk[1][k]);
change(rk[1][z],low[z]);
}
if(rk[p][b]<n){
z=l[p][rk[p][b]+1];
g[b].insert(z);
}
low[a]=rk[1][a];
for(auto k:g[a])chmin(low[a],rk[1][k]);
change(rk[1][a],low[a]);
low[b]=rk[1][b];
for(auto k:g[b])chmin(low[b],rk[1][k]);
change(rk[1][b],low[b]);
}
}
}
}