P5064 [Ynoi Easy Round 2014] 等这场战争结束之后
有撤回操作,可持久化数据结构不好维护,考虑使用操作树。具体的,假设当前是第 \(i\) 次操作,如果是一个撤回 2 x,那么从连一条从 \(x\) 到 \(i\) 的边,否则连一条 \(i-1\) 到 \(i\) 的边。然后以 \(0\) 为根,遍历整颗树,然后操作。
那么现在,只需要一种能维护 \(1,3\) 操作,并支持回溯到前一步的东西就行了。
首先肯定要离散化。
然后考虑使用可撤销并查集实时维护每个点再那个联通块内,然后使用分块。设 \(block_{i,j}\) 表示第 \(i\) 个联通块的点的点权在分块第 \(j\) 块的数量,然后卡卡常就能过了。
一些卡常小技巧
- 交换数组的两维,使内存访问更连续。
- 用链式前向星。
- 开
c++98。 - 根据情况调整块长。
还有,要注意是不是写假了。
代码
/*
Luogu P5064 [Ynoi Easy Round 2014] 等这场战争结束之后
2026-03-06
*/
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
bool be;
const int maxn=100010,len=4000;
int n,m,a[maxn],p[maxn],fa[maxn],sz[maxn],ans[maxn],gs[maxn],bh[maxn],ks;
short block[maxn][100000/len];
struct question{short op;int x,y;}q[maxn];
int head[maxn],nxt[maxn],to[maxn],cnt=0;
void add(int u,int v){nxt[++cnt]=head[u],to[cnt]=v,head[u]=cnt;}
bool en;
int find_root(int u){return fa[u]==0?u:find_root(fa[u]);}
void dfs(int u){
int op=q[u].op,x=q[u].x,y=q[u].y,fax,fay;
if(op==1){
fax=find_root(x),fay=find_root(y);
if(fax!=fay){
if(sz[fax]<sz[fay]) swap(fax,fay);
fa[fay]=fax,sz[fax]+=sz[fay];
for(int i=0;i<=ks;++i) block[fax][i]+=block[fay][i];
}
}
if(op==3){
fax=find_root(x);
if(sz[fax]<y) ans[u]=-1;
else for(int i=0/len;i<=ks;++i){
if(y<=block[fax][i]){
for(int j=i*len+1,_=min(n,i*len+len);j<=_;++j)
if(find_root(bh[j])==fax) if(--y==0){ans[u]=p[j];break;}
break;
}
y-=block[fax][i];
}
}
for(int i=head[u];i;i=nxt[i]) dfs(to[i]);
if(op==1&&fax!=fay){
fa[fay]=0,sz[fax]-=sz[fay];
for(int i=0;i<=ks;++i) block[fax][i]-=block[fay][i];
}
}
signed main(){
read(n,m);
ks=(n-1)/len;
for(int i=1;i<=n;++i) read(a[i]),p[i]=a[i],sz[i]=1;
sort(p+1,p+1+n);
for(int i=1;i<=n;++i){
a[i]=lower_bound(p+1,p+1+n,a[i])-p;
a[i]+=gs[a[i]]++;
bh[a[i]]=i;
}
for(int i=1;i<=n;++i) ++block[i][(a[i]-1)/len];
for(int i=1;i<=m;++i){
short op;int x,y=0;read(op,x);
if(op!=2) read(y);
q[i]={op,x,y};
if(op==2) add(x,i);
else add(i-1,i);
}
dfs(0);
for(int i=1;i<=m;++i) if(q[i].op==3) write(ans[i]),write("\n");
return 0;
}

浙公网安备 33010602011771号