LCT 求调
查看原帖
LCT 求调
520748
_Ch1F4N_楼主2023/9/2 16:14

如题,但是写的是树分块,已过样例和最后几个点

#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;
}
2023/9/2 16:14
加载中...