P6351 [PA2011] Hard Choice 题解
早早地写出了全线性做法,因为要放模拟赛没挂题解。确定性线性做法最早于我于
先以每条边被删除的时间从后到前的顺序建出最小生成树,对于一个询问
简单证明一下,因为是最小生成树,如果有树边没覆盖,那
到这里,有一个最朴素的
但是上面的做法是没有什么前途的,注意到我们做链覆盖和链查询,最后只是为了比较链上最小覆盖次数与
换一种思考方式,该问题等价于我们倒着做,每一条边的存在时间是一段后缀,每次用边去做链覆盖时,如果一条树边被覆盖次数达到
因为每条边最多只被覆盖
这个题很不爽的是给删除的边是以端点给出的,还要写哈希或者 umap。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <unordered_map>
using namespace std;
int n,m,q,tm,cnt;
int f[2000005];
int h[2000005];
int hd[2000005];
int fa[2000005];
int it[2000005];
int dep[2000005];
int dfn[2000005];
int out[2000005];
bool del[2000005];
struct node{int op,x,y;};
node e[2000005];
node g[2000005];
node opt[2000005];
bool ans[2000005];
unordered_map <long long,int> mp;
inline void add(int u,int v,int id){
g[++cnt]={v,hd[u],id},hd[u]=cnt;
g[++cnt]={u,hd[v],id},hd[v]=cnt;
return ;
}
inline void in(int &n){
n=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0'&&c<='9') n=n*10+c-'0',c=getchar();
return ;
}
inline int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
inline void dfs(int u,int f){
fa[u]=f;
dep[u]=dep[f]+1;
dfn[u]=++tm;
for(int i=hd[u];i;i=g[i].x){
int v=g[i].op,id=g[i].y;
if(v==f) continue;
it[v]=id;
dfs(v,u);
}
out[u]=tm;
return ;
}
inline void Cover(int u,int v){
int l=min(dfn[u],dfn[v]),r=max(dfn[u],dfn[v]);
int pos=Find(u);
while(dfn[pos]>l||out[pos]<r){
h[it[pos]]++;
if(h[it[pos]]==2) f[pos]=Find(fa[pos]);
pos=Find(fa[pos]);
}
pos=Find(v);
while(dfn[pos]>l||out[pos]<r){
h[it[pos]]++;
if(h[it[pos]]==2) f[pos]=Find(fa[pos]);
pos=Find(fa[pos]);
}
return ;
}
int main(){
in(n),in(m),in(q);
for(int i=1;i<=m;i++){
int u,v;
in(u),in(v);
mp[1ll*min(u,v)*n+max(u,v)]=i;
e[i]={1,u,v};
}
for(int i=1;i<=q;i++){
char c[3];
scanf("%s",c+1);
if(c[1]=='Z'){
int u,v;
in(u),in(v);
u=mp[1ll*min(u,v)*n+max(u,v)];
del[u]=1;
opt[i]=e[u];
}
else{
int u,v;
in(u),in(v);
opt[i]={2,u,v};
}
}
int tt=0;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++){
if(del[i]) continue;
int u=Find(e[i].x),v=Find(e[i].y);
if(u!=v){
f[u]=v;
add(e[i].x,e[i].y,++tt);
}
}
for(int i=q;i>=1;i--)
if(opt[i].op==1){
int u=Find(opt[i].x),v=Find(opt[i].y);
if(u!=v){
f[u]=v;
add(opt[i].x,opt[i].y,++tt);
}
}
for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i,0);
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++) if(!del[i]) Cover(e[i].x,e[i].y);
tt=0;
for(int i=q;i>=1;i--){
if(opt[i].op==1) Cover(opt[i].x,opt[i].y);
else ans[++tt]=(Find(opt[i].x)==Find(opt[i].y));
}
for(int i=tt;i>=1;i--) puts(ans[i]?"TAK":"NIE");
return 0;
}