ETT是不可能ETT的,这辈子都不可能ETT的,所以就有了这道离线的
直接上线段树分治+并查集就完了
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();};
return res*f;
}
const int N=5e5+10;
int n,m,top,tot1,tot2;
int pt[N],siz[N],fa[N];
int que[N];
map<int,int>mp[N];
struct E{int x,y;}a[N],q[N],sta[N],de[N];
vector<int>tag[N<<2];
namespace bcj{
int get(int v){return v==fa[v]?v:get(fa[v]);}
inline void merge(int x,int y){
x=get(x);y=get(y);
if(x==y) return;
if(siz[x]>siz[y]) swap(x,y);
sta[++top]=(E){x,y};
fa[x]=y;siz[y]+=siz[x];
}
inline void del(int tmp){
while(top>tmp){
int x=sta[top].x,y=sta[top--].y;
fa[x]=x;siz[y]-=siz[x];
}
}
}
using namespace bcj;
namespace segtree{
void ins(int k,int l,int r,int ql,int qr,int id){
if(ql<=l && r<=qr) {tag[k].push_back(id);return;}
int mid=(l+r)>>1;
if(ql<=mid) ins(k<<1,l,mid,ql,qr,id);
if(qr>mid) ins(k<<1|1,mid+1,r,ql,qr,id);
}
void dfs(int k,int l,int r){
int now=top;
for(int i=0;i<tag[k].size();i++) merge(de[tag[k][i]].x,de[tag[k][i]].y);
if(l==r){if(que[l]) puts(get(q[l].x)==get(q[l].y)?"Y":"N");}
else{
int mid=(l+r)>>1;
dfs(k<<1,l,mid);dfs(k<<1|1,mid+1,r);
}
del(now);
}
}
using namespace segtree;
int main(){
n=read();m=read();
for(int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
for(int i=1;i<=m;i++){
int op=read(),x=read(),y=read();
if(x>y) swap(x,y);
if(op==0){
if(pt[mp[x][y]]) continue;
mp[x][y]=++tot1;
a[tot1]=(E){x,y};
pt[mp[x][y]]=i;
}
else if(op==1) {
int id=mp[x][y];
de[++tot2]=(E){x,y};
ins(1,1,m,pt[id],i,tot2);
pt[id]=0;
}
else q[i]=(E){x,y},que[i]=true;
}
for(int i=1;i<=tot1;i++) if(pt[i]){
de[++tot2]=(E){a[i].x,a[i].y};
ins(1,1,m,pt[i],m,tot2);
}
dfs(1,1,m);
return 0;
}
还有一个做法是LCT,维护的是以删除时间为边权的最大生成树,因为如果一个边有一个时刻不在这个生成树上,那么它之后无论怎么变化对答案都不会产生影响,因为树总是连通的,而且树上所有边在它删除之前都不会消失
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int M=5e5+5,N=5e3+5;
struct Q{int op,x,y,tm;}q[M];
int n,m,x[N+M],y[N+M],v[N+M],cnt;
map<ll,int>hs;
namespace LCT{
int fa[N+M],ls[N+M],rs[N+M],rev[N+M],s[N+M];
int que[N+M];
inline int isrs(int x){return x==rs[fa[x]];}
inline bool isroot(int x){
if(!fa[x]) return true;
return ls[fa[x]]!=x && rs[fa[x]]!=x;
}
inline void pushup(int x){
s[x]=x;
if(v[s[ls[x]]]<v[s[x]]) s[x]=s[ls[x]];
if(v[s[rs[x]]]<v[s[x]]) s[x]=s[rs[x]];
}
inline void pushdown(int x){
if(rev[x]){
swap(ls[x],rs[x]);
if(ls[x]) rev[ls[x]]^=1;
if(rs[x]) rev[rs[x]]^=1;
rev[x]=0;
}
}
inline void rotate(int x){
int y=fa[x],z=fa[y],b=ls[y]==x?rs[x]:ls[x];
if(z && !isroot(y)) (ls[z]==y?ls[z]:rs[z])=x;
fa[x]=z,fa[y]=x;b?fa[b]=y:0;
if(ls[y]==x) rs[x]=y,ls[y]=b;
else ls[x]=y,rs[y]=b;
pushup(y);pushup(x);
}
inline void splay(int x){
que[que[0]=1]=x;
for(int y=x;!isroot(y);y=fa[y]) que[++que[0]]=fa[y];
for(int i=que[0];i;i--) pushdown(que[i]);
while(!isroot(x)){
while(!isroot(fa[x])){
if(isrs(x)==isrs(fa[x])) rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x);rs[x]=y;
if(y) fa[y]=x;
pushup(x);
}
}
inline int findroot(int x){
access(x);splay(x);
while(pushdown(x),ls[x]) x=ls[x];
splay(x);return x;
}
inline void makeroot(int x){access(x);splay(x);rev[x]^=1;}
inline void link(int x,int y){makeroot(x);fa[x]=y;}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
inline void cut(int x,int y){split(x,y);ls[y]=fa[x]=0;pushup(y);}
inline int query(int x,int y){split(x,y);return s[y];}
}
using namespace LCT;
inline void add(int xx,int yy,int zz){
s[++cnt]=cnt;v[cnt]=zz;
x[cnt]=xx,y[cnt]=yy;
link(cnt,xx);link(cnt,yy);
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++){
q[i].op=read();q[i].x=read();q[i].y=read();
if(q[i].x>q[i].y) swap(q[i].x,q[i].y);
if(!q[i].op) hs[(ll)q[i].x*m+q[i].y]=i;//hash
else if(q[i].op==1) q[hs[(ll)q[i].x*m+q[i].y]].tm=i;//hash
}
cnt=n;
for(int i=0;i<=n;i++) s[i]=i,v[i]=M;
for(int i=1;i<=m;i++) if(!q[i].op && !q[i].tm) q[i].tm=M;
for(int i=1;i<=m;i++){
if(!q[i].op){
if(findroot(q[i].x)!=findroot(q[i].y)) add(q[i].x,q[i].y,q[i].tm);
else{
int p=query(q[i].x,q[i].y);
if(v[p]<q[i].tm){cut(p,x[p]);cut(p,y[p]);add(q[i].x,q[i].y,q[i].tm);}
}
}
else if(q[i].op==2) (findroot(q[i].x)!=findroot(q[i].y) || v[query(q[i].x,q[i].y)]<i)?puts("N"):puts("Y");
}
return 0;
}