快退役了还写博客,我真是棒棒呢 >_<
这道题网上通用的解法是LCT,虽然LCT的确可以做,不过我还是一直惦记这宦壕从合肥回来以后嚷嚷着这题我是用可持久化并查集+CDQ分治过的
(当然了,他肯定是在吹牛,我怀疑他根本不知道可持久化并查集是什么。。。可回滚并查集和可持久化并查集还是有些区别的
可持久化并查集要用可持久化数组(即可持久化线段树实现),可以回退任意历史版本,但是实际上没什么用,可回滚并查集在cdq分治、莫队中都有很广泛的应用,
他使用按秩合并的方式,保留所有修改,每次将所有修改撤销来实现,实际上就是对某一时刻做副本只能回滚到那一时刻)
我百思不得其解,当然是我比较蠢,以前没见过这类图分治的题
直到前几天要退役了,CCPC-FINAL打了个铜,觉得自己什么都不会,还是学一波吧
这类问题有个非常经典的问题,bzoj 4025
这种动态增删边问题,可以把每条边出现时间都扣出来形成一个区间[st,ed],然后去分治
这种分治的过程很像线段树的查询,复杂度计算也可以参考
cdq维护左区间对右区间的影响实际上是对于左区间维护了一个数据结构(并查集)
并查集维护了rt 该连通块的根 以及 fl 该连通块是否成环了
复杂度应该是O(NlogNlogN)的,但是由于此类题目一般借助LCT,LCT不管怎么写,常数都不小,所以亲测差距不大
学完了发现LCT还有一个最大删除时间生成树,这东西也是妙啊,mark一下
这道题网上通用的解法是LCT,虽然LCT的确可以做,不过我还是一直惦记这宦壕从合肥回来以后嚷嚷着这题我是用可持久化并查集+CDQ分治过的
(当然了,他肯定是在吹牛,我怀疑他根本不知道可持久化并查集是什么。。。可回滚并查集和可持久化并查集还是有些区别的
可持久化并查集要用可持久化数组(即可持久化线段树实现),可以回退任意历史版本,但是实际上没什么用,可回滚并查集在cdq分治、莫队中都有很广泛的应用,
他使用按秩合并的方式,保留所有修改,每次将所有修改撤销来实现,实际上就是对某一时刻做副本只能回滚到那一时刻)
我百思不得其解,当然是我比较蠢,以前没见过这类图分治的题
直到前几天要退役了,CCPC-FINAL打了个铜,觉得自己什么都不会,还是学一波吧
这类问题有个非常经典的问题,bzoj 4025
这种动态增删边问题,可以把每条边出现时间都扣出来形成一个区间[st,ed],然后去分治
这种分治的过程很像线段树的查询,复杂度计算也可以参考
cdq维护左区间对右区间的影响实际上是对于左区间维护了一个数据结构(并查集)
并查集维护了rt 该连通块的根 以及 fl 该连通块是否成环了
复杂度应该是O(NlogNlogN)的,但是由于此类题目一般借助LCT,LCT不管怎么写,常数都不小,所以亲测差距不大
学完了发现LCT还有一个最大删除时间生成树,这东西也是妙啊,mark一下
就还是这类题,有删除时间,对于非树边,如果他将来还要作为非树边,这是十分麻烦的,所以就将环上的最小删除时间的边抠出来删去,把新的边接上,这样就保证从边上换下来的边都不会被再作为树边,这样的话这种类型的题就很好办了,可以方便的用LCT的一棵树维护出一个图。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
#include <string>
#include <iostream>
#include <queue>
#define pii pair<int,int>
#define xx first
#define yy second
#define mp make_pair
#define lson l, mid, x<<1
#define rson mid+1, r, x<<1|1
#define eps 1e-9
#define uint unsigned
using namespace std;
typedef long long ll;
const int N = 4e5+5;
int siz[N], fa[N], rt[N], a[N], cnt = 0, tim[N], q[N], n;
bool fl[N];
vector<int>ans;
struct edge
{
int x, y, s, e;
edge(){}
edge(int _x, int _y, int _s, int _e){
x = _x; y = _y; s = _s; e = _e;
}
};
struct node
{
int id, siz, fa, rt; bool fl;
node(){};
node( int _id, int _siz, int _fa, int _rt, bool _fl ){
id = _id; siz = _siz; fa = _fa; rt = _rt; fl= _fl;
}
}stk[N*30];
void re( node p )
{
int id = p.id;
siz[id] = p.siz;
fa[id] = p.fa;
rt[id] = p.rt;
fl[id] = p.fl;
}
void init( int n )
{
for( int i = 1; i <= n; i ++ ){
fa[i] = i;
rt[i] = i;
siz[i] = 1;
fl[i] = 0;
}
}
int find( int x )
{
if( fa[x] == x ) return x;
else return find(fa[x]);
}
bool merge( int x, int y )//x->y
{
int fx = find(x), fy = find(y);
stk[cnt++] = node( fx, siz[fx], fa[fx], rt[fx], fl[fx] );
if( fx == fy ){
fl[fx] = 1;
return 0;
}
stk[cnt++] = node( fy, siz[fy], fa[fy], rt[fy], fl[fy] );
if( siz[fx] < siz[fy] ){
fa[fx] = fy;
siz[fy] += siz[fx];
}
else{
fa[fy] = fx;
siz[fx] += siz[fy];
}
if( fl[fx] || fl[fy] ) fl[fx] = fl[fy] = 1;
rt[fx] = rt[fy];
return 1;
}
void cdq( int l, int r, vector<edge>& g )
{
int i, j, k, nw = cnt;
// puts("");
// printf("%d %d\n", l, r);
for( auto& v : g ){
if( v.s == l && v.e == r ){
//printf("%d %d %d %d\n", v.x, v.y, v.s, v.e);
merge( v.x, v.y );
}
}
//for( i = 1; i <= n; i ++ ) printf("%d %d %d %d %d\n", i, fa[i], siz[i], rt[i], fl[i] );
if( l == r ){
if( q[l] ){
int v = q[l];
int fx = find(v);
if( fl[fx] == 1 ) ans.push_back(-1);
else{
ans.push_back(rt[fx]);
}
}
return ;
}
vector<edge>L, R;
int mid = (l+r)>>1;
for( auto v : g ){
if( v.s == l && v.e == r ) continue;// !!!
if( v.e <= mid ) L.push_back(v);
else if( v.s > mid ) R.push_back(v);
else{
L.push_back( edge( v.x, v.y, v.s, mid ) );
R.push_back( edge( v.x, v.y, mid+1, v.e ) );
}
}
cdq( l, mid, L );
cdq( mid+1, r, R );
while( cnt > nw ){ re( stk[cnt-1] ); cnt --; }
return ;
}
int main()
{
int m, i, j, k, x, y;
// freopen("in.txt", "r", stdin);
// freopen("wrong.txt", "w", stdout);
scanf("%d%d", &n, &m);
init( n );
for( i = 1; i <= n; i ++ ){
scanf("%d", &a[i]);
tim[i] = 0;
}
vector<edge>ed;
for( i = 1; i <= m; i ++ ){
int id;
scanf("%d", &id);
if( id == 1 ){
scanf("%d%d", &x, &y);
if( a[x] ){
ed.push_back( edge( x, a[x], tim[x], i-1 ) );
}
a[x] = y;
tim[x] = i;
}
else{
scanf("%d", &x);
q[i] = x;
}
}
for( i = 1; i <= n; i ++ ){
if( a[i] ){
ed.push_back( edge( i, a[i], tim[i], m+1 ) );
}
}
//for( auto v : ed ) printf("%d %d %d %d\n", v.x, v.y, v.s, v.e);
cdq( 0, m+1, ed );
for( auto& v : ans ) printf("%d\n", v);
}