如题,但是写的是树分块,已过样例和最后几个点
#include<bits/stdc++.h>
#include<bits/extc++.h>
//#define int long long
//#define lowbit(x) (x&-(x))
using namespace std;
const int maxn = 1e5+114;
const int B = 500;
int fa[maxn];//原树上的父亲
int sz[maxn];//簇的大小
int dep[maxn];
int tot;
int st[maxn],top;//存贮还未分配的边
vector<int> edge[maxn];
int st_top[maxn];
int wait[maxn];//待分配的边
int low[maxn];//最浅界点
int CL[maxn],CLtot;
int CL_up[maxn],CL_down[maxn];//所属簇的上界点 (若为界点,则其所属簇为其作为下界点时所属的簇)
vector<int> CLedge[maxn];//收缩树上的边
int Point[maxn];//点权
__gnu_pbds::gp_hash_table<int,int> w[maxn];
vector<int> road[maxn];//临时用边
bool vis[maxn];
int CLpos;
int found[maxn];
vector<int> G[maxn];//每个簇的点集
int rfa[maxn];//反转后的父亲
int tag[maxn];//反转标记
bool isCL[maxn];//是否是 boundary node
vector<int> E[maxn];
__gnu_pbds::gp_hash_table<int,int> isE[maxn];//边是否存在
int n,q;
void copy(){
for(int i=1;i<=n;i++){
edge[i].clear();
for(int x:E[i]){
if(isE[i][x]==true){
edge[i].push_back(x);
}
}
E[i].clear();
}
for(int i=1;i<=n;i++){
for(int x:edge[i]){
E[i].push_back(x);
}
}
}//重构整张图
int Root[maxn];//一个点是否是根
int findroot(int u,int father){
if(Root[u]==true) return u;
for(int v:CLedge[u]){
if(v==father) continue;
int res=findroot(v,u);
if(res!=-1) return res;
}
return -1;
}
void dfs_init1(int u){
for(int v:edge[u]){
if(vis[v]==false) continue;
road[u].push_back(v);
road[v].push_back(u);
dfs_init1(v);
}
}
void dfs_init2(int u,int father){
rfa[u]=father;
for(int v:road[u]){
if(v==father) continue;
dfs_init2(v,u);
}
}
void add_CL(int u,int v){//新建一个簇
CLpos++;
if(CLtot==0){
G[u].push_back(u);
return ;
}
if(!v) v=CL[CLtot];
isCL[u]=isCL[v]=true;
CLedge[u].push_back(v);
CLedge[v].push_back(u);
int res=0;
for(int r=fa[v];r!=u;r=fa[r])
res^=Point[r];
w[u][v]=w[v][u]=res;
vis[u]=true;
G[CLpos].push_back(u);
for(int i=1;i<=CLtot;i++){
int r=CL[i];
if(r!=v){
found[i]=CLpos;
}
G[CLpos].push_back(r);
vis[r]=true;
CL_up[r]=u;
CL_down[r]=v;
road[r].clear();
}
dfs_init1(u);
dfs_init2(v,0);
vis[u]=false;
for(int i=1;i<=CLtot;i++) vis[CL[i]]=false;
CLtot=0;
}
void build(int u,int father){
fa[u]=father;
dep[u]=dep[father]+1;
st_top[u]=top;
for(auto it=edge[u].begin();it!=edge[u].end();it++)
if((*it)==father){
edge[u].erase(it);
break;
}
wait[u]=true;
int cnt=0;
for(int v:edge[u]){
st[++top]=v;
build(v,u);
wait[u]+=wait[v];
low[v]&&(low[u]=low[v],cnt++);
}
if(wait[u]>B||cnt>1||father==0){
wait[u]=0,low[u]=u;
for(int i=0,j=st_top[u]+1,Cnt=0,cur_down=0,v;i<=edge[u].size();i++){
// Cnt 簇的大小 cur_down 簇的下界点
v=(i==edge[u].size())?0:edge[u][i];
if(Cnt+wait[v]>B||(cur_down&&low[v])||!v){ //已无法往当前簇中再加入一个子树
for (;(j<st_top[v]||!v)&&j<=top;j++)
CL[++CLtot]=st[j];
add_CL(u,cur_down),Cnt=cur_down=0;
}
Cnt+=wait[v],low[v]&&(cur_down=low[v]);
}
top=st_top[u];
}
}
int dfs_query(int u,int fa,int to){
if(u==to){
return Point[u];
}
for(int v:CLedge[u]){
if(v==fa) continue;
int res=dfs_query(v,u,to);
if(res!=-1){
return res^Point[u]^w[u][v];
}
}
return -1;
}
int LCA(int u,int v){
while(u!=v){
if(dep[u]<dep[v]) swap(u,v);
u=fa[u];
}
return u;
}
int ask(int u){
int res=0;
int pos=CL_up[u];
if(tag[CL_up[u]]==0){
while(isCL[u]==false) res^=Point[u],u=fa[u];
}
else{
while(isCL[u]==false){
res^=Point[u],u=rfa[u];
}
}
res^=dfs_query(findroot(u,0),0,u);
return res;
}
bool use[maxn];
void mx_block(int u){
use[u]=true;
for(int v:edge[u]){
if(vis[v]==false) continue;
mx_block(v);
}
}
void makeboundary(int u){
if(isCL[u]==true) return;
int DOWN=CL_down[u],UP=CL_up[u];
int lca=LCA(DOWN,u);
if(lca==UP){
int lower=u;
while(fa[lower]!=UP) lower=fa[lower];
for(int x:G[found[u]]) vis[x]=true;
mx_block(lower);
for(int x:G[found[u]]) vis[x]=false;
vector<int> New,Vec;
for(int x:G[found[u]]){
if(use[x]==false) New.push_back(x);
else Vec.push_back(x);
use[x]=false;
}
for(auto it = CLedge[UP].begin();it!=CLedge[UP].end();++it){
if((*it)==DOWN){
CLedge[UP].erase(it);
break;
}
}
for(auto it = CLedge[DOWN].begin();it!=CLedge[DOWN].end();++it){
if((*it)==UP){
CLedge[DOWN].erase(it);
break;
}
}
G[found[u]].clear();
CLtot=0;
for(int x:New) if(x!=UP) CL[++CLtot]=x;
add_CL(UP,DOWN);
CLtot=0;
for(int x:Vec) if(x!=UP) CL[++CLtot]=x;
add_CL(UP,u);
}
else if(lca==u){
for(int x:G[found[u]]) vis[x]=true;
mx_block(u);
for(int x:G[found[u]]) vis[x]=false;
vector<int> New,Vec;
for(int x:G[found[u]]){
if(use[x]==false) New.push_back(x);
else Vec.push_back(x);
use[x]=false;
}
G[found[u]].clear();
CLtot=0;
for(int x:New) if(x!=UP) CL[++CLtot]=x;
CL[++CLtot]=u;
add_CL(UP,u);
CLtot=0;
for(int x:Vec) if(x!=u) CL[++CLtot]=x;
add_CL(u,DOWN);
for(auto it = CLedge[UP].begin();it!=CLedge[UP].end();++it){
if((*it)==DOWN){
CLedge[UP].erase(it);
break;
}
}
for(auto it = CLedge[DOWN].begin();it!=CLedge[DOWN].end();++it){
if((*it)==UP){
CLedge[DOWN].erase(it);
break;
}
}
}
else if(lca==DOWN){
for(int x:G[found[u]]) vis[x]=true;
mx_block(DOWN);
for(int x:G[found[u]]) vis[x]=false;
vector<int> New,Vec;
for(int x:G[found[u]]){
if(use[x]==false) New.push_back(x);
else Vec.push_back(x);
use[x]=false;
}
G[found[u]].clear();
CLtot=0;
for(int x:New) if(x!=UP) CL[++CLtot]=x;
CL[++CLtot]=DOWN;
add_CL(UP,DOWN);
CLtot=0;
for(int x:Vec) if(x!=DOWN) CL[++CLtot]=x;
add_CL(DOWN,u);
for(auto it = CLedge[DOWN].begin();it!=CLedge[DOWN].end();it++){
if((*it)!=UP) CLedge[u].push_back((*it));
}
}
else{
//这个时候要把这个 cluster 裂成 lca to up down to lca u to lca 三个部分
int lower=DOWN;
vector<int> Vec1,Vec2,New;
while(fa[lower]!=lca) lower=fa[lower];
for(int x:G[found[u]]) vis[x]=true;
mx_block(lower);
for(int x:G[found[u]]){
if(use[x]==true){
vis[x]=false;
Vec1.push_back(x);
}
use[x]=false;
}
lower=u;
while(fa[u]!=UP) u=fa[u];
mx_block(lower);
for(int x:G[found[u]]){
if(use[x]==true){
vis[x]=false;
Vec2.push_back(x);
}
use[x]=false;
}
for(int x:G[found[u]]){
if(vis[x]==false) New.push_back(x);
}
G[found[u]].clear();
CLtot=0;
for(int x:New){
if(x!=UP) CL[++CLtot]=x;
}
CL[++CLtot]=lca;
add_CL(UP,lca);
CLtot=0;
for(int x:Vec1){
if(x!=lca) CL[++CLtot]=x;
}
add_CL(lca,DOWN);
CLtot=0;
for(int x:Vec2){
if(x!=lca) CL[++CLtot]=x;
}
add_CL(lca,u);
for(auto it = CLedge[UP].begin();it!=CLedge[UP].end();++it){
if((*it)==DOWN){
CLedge[UP].erase(it);
break;
}
}
for(auto it = CLedge[DOWN].begin();it!=CLedge[DOWN].end();++it){
if((*it)==UP){
CLedge[DOWN].erase(it);
break;
}
}
}
}
void dfs_Re(int u,int father,int to,bool type){
if(type==true) tag[u]^=1;
for(int v:CLedge[u]){
if(v==father) continue;
dfs_Re(v,u,to,type&&(v!=to));
}
}
void makeroot(int u){
if(Root[u]==true) return ;
makeboundary(u);
int rt=findroot(u,0);
dfs_Re(rt,0,u,true);
Root[rt]=false;
Root[u]=true;
}
void link(int u,int v){
if(findroot(u,0)==findroot(v,0)) return ;
isE[u][v]=isE[v][u]=true;
makeroot(u);
makeroot(v);
Root[v]=false;
E[u].push_back(v);
E[v].push_back(u);
CLedge[u].push_back(v);
CLedge[v].push_back(u);
w[u][v]=w[v][u]=0;
CL_down[v]=v;
CL_up[v]=u;
}
void cut(int u,int v){
if(isE[u][v]==false) return ;
isE[u][v]=isE[v][u]=false;
makeroot(u);
makeboundary(v);
for(auto it=CLedge[u].begin();it!=CLedge[u].end();++it){
if((*it)==v){
CLedge[u].erase(it);
break;
}
}
for(auto it=CLedge[v].begin();it!=CLedge[v].end();++it){
if((*it)==u){
CLedge[v].erase(it);
break;
}
}
Root[v]=true;
makeroot(v);
}
void maintain(){
copy();
for(int i=1;i<=CLpos;i++) G[i].clear();
CLpos=0;
memset(fa,0,sizeof(fa));
memset(sz,0,sizeof(sz));
memset(wait,0,sizeof(wait));
memset(low,0,sizeof(low));
memset(CL,0,sizeof(CL));
memset(CL_up,0,sizeof(CL_up));
memset(CL_down,0,sizeof(CL_down));
memset(dep,0,sizeof(dep));
memset(tag,0,sizeof(tag));
memset(isCL,0,sizeof(isCL));
memset(vis,0,sizeof(vis));
memset(Root,0,sizeof(Root));
memset(rfa,0,sizeof(rfa));
memset(found,0,sizeof(found));
memset(sz,0,sizeof(sz));
top=0;
CLtot=0;
for(int i=1;i<=n;i++) w[i].clear(),CLedge[i].clear();
for(int i=1;i<=n;i++){
if(dep[i]==0) Root[i]=true,isCL[i]=true,build(i,0);
}
return ;
}
void Output(int u,int father){
cout<<u<<'\n';
for(int v:CLedge[u]){
if(v!=father) Output(v,u);
}
cout<<u<<'\n';
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
maintain();
for(int i=1;i<=n;i++) cin>>Point[i];
for(int i=1;i<=q;i++){
if(i%B==0) maintain();
int opt,x,y;
cin>>opt>>x>>y;
if(opt==0){
makeroot(x);
cout<<ask(y)<<'\n';
}
else if(opt==1){
link(x,y);
}
else if(opt==2){
cut(x,y);
}
else{
Point[x]=y;
if(isCL[x]==false) add_CL(CL_up[x],CL_up[y]);
}
}
return 0;
}