洛谷 P9358 [ICPC2022 Xi'an R] Bridge(Splay)
传送门
解题思路
把每个国家的城市看成一条链。
那么建桥操作相当于将两条链的某处断开,然后交换断点后面的部分。
查询操作就是从链首开始找到链尾属于哪个国家。
这些操作可以由Splay平衡树来维护。
相当于开n个平衡树。
但是总点数O(NM)会爆炸,所以我们考虑实际用到的点只有O(N+Q),所以每个点实际上代表着一段区间(初始状态为每一棵平衡树只有一个点1~m+1)。
在b处建桥操作时就是将一个[L,R]的点劈开,分成两个点[L,b],[b+1,R],然后将[L,b]点Splay到根,两个右儿子进行交换即可。
同时要用set维护b位置所属的区间的平衡树上的编号(比较琐碎 ,难写)。
调了好久qwq
AC代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!(c>='0'&&c<='9')) {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return x*f;
}
#define mp(a,b) make_pair(a,b)
#define pii pair<int,int>
const int maxn=2e5+5;
set<pii> s[maxn];
int rt[maxn],cnt,n,m,q;
struct node{
int l,r,fa,son[2],rk,val;
}tr[maxn*4];
void rotate(int x){
int y=tr[x].fa,z=tr[y].fa;
int c=(tr[y].son[1]==x);
tr[tr[x].son[!c]].fa=y;
tr[y].fa=x;
tr[x].fa=z;
tr[y].son[c]=tr[x].son[!c];
tr[x].son[!c]=y;
if(z) tr[z].son[tr[z].son[1]==y]=x;
tr[x].rk=tr[y].rk;
}
void splay(int x){
while(tr[x].fa){
int y=tr[x].fa,z=tr[y].fa;
if(z) ((tr[y].son[0]==x)^(tr[z].son[0]==y))?rotate(x):rotate(y);
rotate(x);
}
rt[tr[x].rk]=x;
}
void add(int r,int x){
cnt++;
tr[cnt].fa=0;
tr[x].fa=cnt;
tr[cnt].l=tr[x].l;
tr[cnt].r=r;
tr[x].l=r+1;
tr[cnt].son[0]=tr[x].son[0];
tr[tr[x].son[0]].fa=cnt;
tr[x].son[0]=0;
tr[cnt].son[1]=x;
tr[cnt].rk=tr[x].rk;
rt[tr[x].rk]=cnt;
tr[cnt].val=tr[x].val;
}
void Swap(int x,int y){
swap(tr[x].fa,tr[y].fa);
swap(tr[x].rk,tr[y].rk);
tr[tr[x].fa].son[1]=x;
tr[tr[y].fa].son[1]=y;
}
int findMax(int x){
while(tr[x].fa) x=tr[x].fa;
while(tr[x].son[1]) x=tr[x].son[1];
return x;
}
int main()
{
n=read(),m=read()+1,q=read();
for(int i=1;i<=n;i++){
rt[i]=++cnt;
tr[cnt].l=1;
tr[cnt].r=m;
tr[cnt].val=i;
tr[cnt].rk=i;
s[i].insert(mp(m,cnt));
}
while(q--){
int tp=read();
if(tp==1){
int a=read(),b=read();
auto it=s[a].lower_bound(mp(b,0));
int x=(*it).second;
auto it2=s[a+1].lower_bound(mp(b,0));
int y=(*it2).second;
splay(x);
add(b,x);
s[a].insert(mp(b,cnt));
splay(y);
add(b,y);
s[a+1].insert(mp(b,cnt));
Swap(x,y);
}else{
int a=read();
printf("%d\n",findMax(rt[a]));
}
// for(int i=1;i<=cnt;i++) printf("id:%d val:%d fa:%d l:%d r:%d rk:%d\n",i,tr[i].val,tr[i].fa,tr[i].l,tr[i].r,tr[i].rk);
}
return 0;
}