Solution Set - LCT
A[洛谷P3690]维护一个森林,支持询问路径xor和,连边(已连通则忽略),删边(无边则忽略),改变点权。
B[洛谷P3203]\(n\)个装置编号为\(0,...,n-1\),从\(i\)可以一步跳到\(i+k_i\),支持修改\(k_i\),询问从一个点开始几步跳出\(n-1\)。
C[洛谷P2486]给定一棵树,点有颜色,支持路径覆盖,询问路径颜色段数。
D[洛谷P4332]给定一棵树,前\(n\)个点各有三个儿子,叶子结点有权\(0/1\),分支结点的权是其三个儿子权值中较多的一个。支持修改叶子结点权值,询问根节点权值。
E[洛谷P2147]维护一个森林,支持连边,删边,询问连通性。
F[洛谷P2542]维护一个图,支持删边,询问两点间必须边数目。
G[洛谷P4234]求给定无向图的最小差值生成树。(最大权与最小权之差)
H[洛谷P4172]维护一个图,支持删边,询问两点间路径最大权的最小值。
I[洛谷P4180]求给定无向图的严格次小生成树。
J[洛谷P4219]维护一个森林,支持加边,询问经过某条边的简单路径数目。
K[洛谷P4299]维护一个森林,支持加边,询问某棵子树重心编号,询问所有子树重心编号的xor和。
LCT:解决动态树问题的一种数据结构。思想是对树做虚实链剖分(每个点随便选一个实儿子),用Splay维护每条实链。由于Splay的灵活性,可以方便地改变虚边和实边。LCT的核心操作包括:①将一个点到根的路径打通为实链(access
);②将一个点设为根(makeroot
)。由此可以实现提取路径(split(x,y)=makeroot(x),access(y)
),连边(link(x,y)=makeroot(x),fa[x]=y
),删边(cut(x,y)=split(x,y),ch[y][0]=fa[x]=0
),查找根(findroot
)。
A模板。
B连边\(i \to \min(i+k_i,n)\),修改时删边,加边,询问时split(i,n)
。
C和Splay专题中打标记的思想是类似的。push_up也很好写。
D把儿子中\(1\)的数量看做关键码。将\(0\)改成\(1\)就修改它向上关键码为\(1\)的点,将\(1\)改成\(0\)就修改它向上关键码为\(2\)的点。那么只用实现区间加,维护最深的\(1\),\(2\)。
E模板。
F用LCT维护边双。注意只用删边,可以倒过来考虑加边。然后用并查集维护边双。两点间第一次连通就在LCT上正常加边,第二次就合并相应的并查集,并遍历整条路径。
LCT维护边权时,可以考虑拆边。
G按边权排序,从小到大枚举最大边,加入最大边时删去其两端点路径上的最小边,并维护选入的最小边权。
H维护瓶颈生成树。也是倒着加边,加入某条边时尝试替换最大边。
I先求最小生成树,然后尝试加入每条边,取出该链上的最小值或次小值更新答案。如果用LCT写,不用删边,只要询问两点间最小边权和次小边权。
LCT维护子树信息时,采用的思想类似于动态DP,即维护所有虚儿子的信息之和。只用在access
和link
中更新。注意link
中要写成makeroot(x),makeroot(y)
,否则会WA。
J模板。询问时可以考虑先删去,然后统计答案,再连回去。
K注意到合并两棵树时,新重心一定在原来的两个重心间的路径上。那么可以提出该路径,在它的Splay上做二分。
点击查看A题代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=3e5+5;
int n,m;map<pii,bool> M;
int fa[N],ch[N][2],val[N],sum[N],tag[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){sum[p]=sum[ls]^sum[rs]^val[p];}
void pushr(int p){tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;if(ls)pushr(ls);if(rs)pushr(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isRoot(int p){return ch[fa[p]][0]!=p&&ch[fa[p]][1]!=p;}
void update(int p){if(!isRoot(p))update(fa[p]);push_down(p);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isRoot(y))ch[z][y==ch[z][1]]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;
push_up(y);push_up(x);
}
void splay(int x){
update(x);
for(int p=fa[x];!isRoot(x);p=fa[x]){
if(!isRoot(p))rotate(get(p)==get(x)?p:x);
rotate(x);
}
}
void Access(int x){
for(int y=0;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,push_up(x);
}
int findRoot(int p){
Access(p);splay(p);
while(ls)push_down(p),p=ls;
splay(p);return p;
}
void makeRoot(int p){Access(p);splay(p);pushr(p);}
void split(int x,int y){makeRoot(x);Access(y);splay(y);}
bool link(int x,int y){
makeRoot(x);
if(findRoot(y)==x)return false;
fa[x]=y;return true;
}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
#undef ls
#undef rs
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",val+i);
for(int op,x,y;m--;){
scanf("%d%d%d",&op,&x,&y);
if(op==0)split(x,y),printf("%d\n",sum[y]);
if(op==1)if(link(x,y))M[pii(x,y)]=M[pii(y,x)]=1;
if(op==2)if(M[pii(x,y)])cut(x,y),M[pii(x,y)]=M[pii(y,x)]=0;
if(op==3)splay(x),val[x]=y;
}
return 0;
}
点击查看B题代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,a[N];
int fa[N],ch[N][2],sum[N],tag[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){sum[p]=sum[ls]+sum[rs]+1;}
void pushr(int p){tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;if(ls)pushr(ls);if(rs)pushr(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][y==ch[z][1]]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(y)==get(x)?y:x);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
void makeroot(int p){access(p);splay(p);pushr(p);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
#undef ls
#undef rs
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
link(i,min(n+1,i+a[i]));
}
scanf("%d",&m);
for(int i=1,op,x;i<=m;i++){
scanf("%d%d",&op,&x);++x;
if(op==1)split(x,n+1),printf("%d\n",sum[n+1]-1);
else cut(x,min(n+1,x+a[x])),scanf("%d",a+x),link(x,min(n+1,x+a[x]));
}
return 0;
}
点击查看C题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;char op[3];
int fa[N],ch[N][2],tag[N][2],col[N],lc[N],rc[N],sum[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){
if(ls)lc[p]=lc[ls];else lc[p]=col[p];
if(rs)rc[p]=rc[rs];else rc[p]=col[p];
sum[p]=sum[ls]+sum[rs]+1-(col[p]==rc[ls])-(col[p]==lc[rs]);
}
void make_tag(int p,int op){
if(op==0)tag[p][0]^=1,swap(ls,rs),swap(lc[p],rc[p]);
else tag[p][1]=lc[p]=rc[p]=col[p]=op,sum[p]=1;
}
void push_down(int p){
if(tag[p][0]){tag[p][0]=0;if(ls)make_tag(ls,0);if(rs)make_tag(rs,0);}
if(tag[p][1]){
int v=tag[p][1];tag[p][1]=0;
if(ls)make_tag(ls,v);if(rs)make_tag(rs,v);
}
}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][y==ch[z][1]]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(y)==get(x)?y:x);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
void makeroot(int p){access(p);splay(p);make_tag(p,0);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
#undef ls
#undef rs
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",col+i);
for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),link(u,v);
for(int i=1,u,v,w;i<=m;i++){
scanf("%s",op);
if(op[0]=='C')scanf("%d%d%d",&u,&v,&w),split(u,v),make_tag(v,w);
else scanf("%d%d",&u,&v),split(u,v),printf("%d\n",sum[v]);
}
return 0;
}
点击查看D题代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,m,ans;
int fa[N*3],ch[N][2],val[N*3],n1[N],n2[N],tag[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){
if(n1[rs])n1[p]=n1[rs];else if(val[p]!=1)n1[p]=p;else n1[p]=n1[ls];
if(n2[rs])n2[p]=n2[rs];else if(val[p]!=2)n2[p]=p;else n2[p]=n2[ls];
}
void make_tag(int p,int op){tag[p]+=op;val[p]^=3;swap(n1[p],n2[p]);}
void push_down(int p){
if(tag[p]){
if(ls)make_tag(ls,tag[p]);
if(rs)make_tag(rs,tag[p]);
tag[p]=0;
}
}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][y==ch[z][1]]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(x)==get(y)?y:x);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
int head[N*3],nxt[N*3],ver[N*3],tot;
void add(int u,int v){ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
void dfs(int u){
for(int i=head[u],v;i;i=nxt[i])
dfs(v=ver[i]),val[u]+=val[v]/2;
}
int main(){
scanf("%d",&n);
for(int u=1,v1,v2,v3;u<=n;u++){
scanf("%d%d%d",&v1,&v2,&v3);
add(u,v1);add(u,v2);add(u,v3);
fa[v1]=fa[v2]=fa[v3]=u;
}
for(int i=n+1,x;i<=3*n+1;i++)scanf("%d",&x),val[i]=2*x;
dfs(1);ans=val[1]/2;
scanf("%d",&m);
for(int i=1,p;i<=m;i++){
scanf("%d",&p);
if(val[p]==0){
val[p]=2;access(p=fa[p]);splay(p);
if(!n1[p]){make_tag(p,1);ans^=1;}
else{splay(p=n1[p]);make_tag(rs,1);++val[p];push_up(p);}
}
else{
val[p]=0;access(p=fa[p]);splay(p);
if(!n2[p]){make_tag(p,-1);ans^=1;}
else{splay(p=n2[p]);make_tag(rs,-1);--val[p];push_up(p);}
}
printf("%d\n",ans);
}
return 0;
}
点击查看E题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;char op[15];
int fa[N],ch[N][2],tag[N];
#define ls ch[p][0]
#define rs ch[p][1]
void make_tag(int p){tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;if(ls)make_tag(ls);if(rs)make_tag(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][y==ch[z][1]]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;
}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(y)==get(x)?y:x);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y;}
int findroot(int p){
access(p);splay(p);
while(ls)push_down(p),p=ls;
splay(p);return p;
}
void makeroot(int p){access(p);splay(p);make_tag(p);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;}
bool check(int x,int y){makeroot(x);return findroot(y)==x;}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;i++){
scanf("%s",op);
scanf("%d%d",&u,&v);
if(op[0]=='C')link(u,v);
if(op[0]=='D')cut(u,v);
if(op[0]=='Q')printf(check(u,v)?"Yes\n":"No\n");
}
return 0;
}
点击查看F题代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=1e5+5;
int n,m,k,q[N][3];map<pii,int> M;stack<int> ans;
struct Disjoint_Set{
int fa[N];
void init(int n){for(int i=1;i<=n;i++)fa[i]=i;}
int find(int x){return x==fa[x]?x:(fa[x]=find(fa[x]));}
void Union(int x,int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}
}S;
int fa[N],ch[N][2],tag[N],sum[N];
#define ls ch[p][0]
#define rs ch[p][1]
#define ref S.find(fa[p])
void push_up(int p){sum[p]=sum[ls]+sum[rs]+1;}
void make_tag(int p){if(!p)return;tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;make_tag(ls);make_tag(rs);}}
bool get(int p){return p==ch[ref][1];}
bool isroot(int p){return p!=ch[ref][0]&&p!=ch[ref][1];}
void update(int p){if(!isroot(p))update(ref);push_down(p);}
void rotate(int x){
x=S.find(x);
int y=S.find(fa[x]),z=S.find(fa[y]),op=get(x)^1;
if(!isroot(y))ch[z][get(y)]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int p){
update(p);
for(int x=ref;!isroot(p);x=ref){
if(!isroot(x))rotate(get(x)==get(p)?x:p);
rotate(p);
}
}
void access(int p){for(int x=0;p;x=p,p=ref)splay(p),ch[p][1]=x,push_up(p);}
int findroot(int p){
p=S.find(p);access(p);splay(p);
while(ls)push_down(p),p=ls;
splay(p);return p;
}
void makeroot(int p){p=S.find(p);access(p);splay(p);make_tag(p);}
void dfs(int p,int q){
push_down(p);S.Union(p,q);
if(ch[p][0])dfs(ch[p][0],q);
if(ch[p][1])dfs(ch[p][1],q);
}
void link(int x,int y){
x=S.find(x);y=S.find(y);makeroot(x);
if(findroot(y)!=x){fa[x]=y;return;}
dfs(x,x);
}
void split(int x,int y){makeroot(x);access(y);splay(y);}
int query(int x,int y){x=S.find(x);y=S.find(y);split(x,y);return sum[y];}
#undef ls
#undef rs
int main(){
scanf("%d%d",&n,&m);S.init(n);
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
if(u>v)swap(u,v);
M[pii(u,v)]=1;
}
for(k=1;scanf("%d",&q[k][0]),q[k][0]!=-1;k++){
scanf("%d%d",&q[k][1],&q[k][2]);
if(q[k][1]>q[k][2])swap(q[k][1],q[k][2]);
if(q[k][0]==0)M[pii(q[k][1],q[k][2])]=0;
}--k;
for(auto x:M)if(x.second)link(x.first.first,x.first.second);
for(int i=k;i>=1;i--){
if(q[i][0]==0)link(q[i][1],q[i][2]);
else ans.push(query(q[i][1],q[i][2])-1);
}
while(!ans.empty())printf("%d\n",ans.top()),ans.pop();
return 0;
}
点击查看G题代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
int n,m,cnt,ans=1e9,vis[N],l;
struct edge{int u,v,w;}e[N];
bool operator <(const edge&a,const edge&b){return a.w<b.w;}
int fa[N],ch[N][2],tag[N],mn[N],val[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){mn[p]=min(min(mn[ls],mn[rs]),val[p]);}
void make_tag(int p){if(!p)return;tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;make_tag(ls);make_tag(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][get(y)]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(y)==get(x)?y:x);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
int findroot(int p){access(p);splay(p);while(ls)push_down(p),p=ls;splay(p);return p;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
#undef ls
#undef rs
int main(){
memset(mn,0x3f,sizeof(mn));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w),val[i]=i;
for(int i=m+1;i<=m+n;i++)val[i]=1e9;
sort(e+1,e+m+1);
for(int i=1;i<=m;i++){
if(e[i].u==e[i].v)continue;
++cnt;vis[i]=1;int x=e[i].u+m,y=e[i].v+m;
if(findroot(x)==findroot(y)){
--cnt;split(x,y);int t=mn[y];
cut(e[t].u+m,t);cut(e[t].v+m,t);vis[t]=0;
}
link(x,i);link(y,i);
while(!vis[l]&&l<=m)++l;
if(cnt==n-1)ans=min(ans,e[i].w-e[l].w);
}
printf("%d\n",ans);
return 0;
}
点击查看H题代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=2e5+5;
int n,m,k,vis[N];map<pii,int> M;stack<int> ans;
struct edge{int u,v,w;}e[N],q[N];
bool operator <(const edge&a,const edge&b){return a.w<b.w;}
int fa[N],ch[N][2],tag[N],val[N],mx[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){mx[p]=max(max(mx[ls],mx[rs]),val[p]);}
void make_tag(int p){if(!p)return;tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;make_tag(ls);make_tag(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][get(y)]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(y)==get(x)?y:x);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
int findroot(int p){access(p);splay(p);while(ls)push_down(p),p=ls;splay(p);return p;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
#undef ls
#undef rs
void link(int s){
int x=e[s].u+m,y=e[s].v+m;
if(findroot(x)==findroot(y)){
split(x,y);int t=mx[y];
if(e[t].w<=e[s].w)return;
cut(e[t].u+m,t);cut(e[t].v+m,t);
}
link(x,s);link(y,s);
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
if(e[i].u>e[i].v)swap(e[i].u,e[i].v);
}
sort(e+1,e+m+1);
for(int i=1;i<=m;i++)
M[pii(e[i].u,e[i].v)]=i,val[i]=i;
for(int i=1;i<=k;i++){
scanf("%d%d%d",&q[i].w,&q[i].u,&q[i].v);
if(q[i].u>q[i].v)swap(q[i].u,q[i].v);
if(q[i].w==2)vis[M[pii(q[i].u,q[i].v)]]=1;
}
for(int i=1;i<=m;i++)if(!vis[i])link(i);
for(int i=k;i>=1;i--){
if(q[i].w==2)link(M[pii(q[i].u,q[i].v)]);
else{
split(q[i].u+m,q[i].v+m);
ans.push(e[mx[q[i].v+m]].w);
}
}
while(!ans.empty())printf("%d\n",ans.top()),ans.pop();
return 0;
}
点击查看I题代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5,INF=1<<30;
int n,m,vis[N],res=INF,cnt;long long ans;
struct edge{int u,v,w;}e[N];
bool operator <(const edge&a,const edge&b){return a.w<b.w;}
int fa[N],ch[N][2],tag[N],val[N],mx[N][2];
#define ls ch[x][0]
#define rs ch[x][1]
void push_up(int x){
mx[x][0]=max(max(mx[ls][0],mx[rs][0]),val[x]);mx[x][1]=-INF;
if(mx[ls][0]<mx[x][0])mx[x][1]=max(mx[x][1],mx[ls][0]);
else mx[x][1]=max(mx[x][1],mx[ls][1]);
if(mx[rs][0]<mx[x][0])mx[x][1]=max(mx[x][1],mx[rs][0]);
else mx[x][1]=max(mx[x][1],mx[rs][1]);
if(val[x]<mx[x][0])mx[x][1]=max(mx[x][1],val[x]);
}
void make_tag(int x){if(!x)return;tag[x]^=1;swap(ls,rs);}
void push_down(int x){if(tag[x]){tag[x]=0;make_tag(ls);make_tag(rs);}}
bool get(int x){return x==ch[fa[x]][1];}
bool isroot(int x){return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];}
void update(int x){if(!isroot(x))update(fa[x]);push_down(x);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][get(y)]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(y)==get(x)?y:x);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
int findroot(int x){access(x);splay(x);while(ls)push_down(x),x=ls;splay(x);return x;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
#undef ls
#undef rs
void link(int s){
int x=e[s].u+m,y=e[s].v+m;
if(findroot(x)==findroot(y))return;
ans+=e[s].w;vis[s]=1;++cnt;link(x,s);link(y,s);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
sort(e+1,e+m+1);
for(int i=1;i<=m&&cnt<n-1;i++){val[i]=e[i].w;if(e[i].u!=e[i].v)link(i);}
for(int i=1;i<=m;i++)if(!vis[i]&&e[i].u!=e[i].v){
int u=e[i].u+m,v=e[i].v+m;split(u,v);
if(mx[v][0]==e[i].w)res=min(res,e[i].w-mx[v][1]);
else res=min(res,e[i].w-mx[v][0]);
}
printf("%lld\n",res+ans);
return 0;
}
点击查看J题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;char op[3];
int fa[N],ch[N][2],tag[N],siz[N],siz2[N];
#define ls ch[x][0]
#define rs ch[x][1]
void push_up(int x){siz[x]=siz[ls]+siz[rs]+1+siz2[x];}
void make_tag(int x){if(!x)return;tag[x]^=1;swap(ls,rs);}
void push_down(int x){if(tag[x]){tag[x]=0;make_tag(ls);make_tag(rs);}}
bool get(int x){return x==ch[fa[x]][1];}
bool isroot(int x){return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];}
void update(int x){if(!isroot(x))update(fa[x]);push_down(x);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][get(y)]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(y)==get(x)?y:x);
rotate(x);
}
}
void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x);siz2[x]+=siz[ch[x][1]]-siz[y];
ch[x][1]=y;push_up(x);
}
}
int findroot(int x){access(x);splay(x);while(ls)push_down(x),x=ls;splay(x);return x;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
void link(int x,int y){makeroot(x);makeroot(y);fa[x]=y;siz2[y]+=siz[x];}
#undef ls
#undef rs
int main(){
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;i++){
scanf("%s",op);scanf("%d%d",&u,&v);
if(op[0]=='A')link(u,v);
else{
cut(u,v);makeroot(u);makeroot(v);
printf("%lld\n",1ll*siz[u]*siz[v]);
link(u,v);
}
}
return 0;
}
点击查看K题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,ans;char op[5];
struct Disjoint_Set{
int fa[N],siz[N];
void init(int n){for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;}
int find(int x){return x==fa[x]?x:(fa[x]=find(fa[x]));}
void Union(int x,int y){x=find(x);y=find(y);if(x!=y)fa[x]=y,siz[y]+=siz[x];}
}S;
int fa[N],ch[N][2],tag[N],siz[N],siz2[N];
#define ls ch[x][0]
#define rs ch[x][1]
void push_up(int x){siz[x]=siz[ls]+siz[rs]+1+siz2[x];}
void make_tag(int x){if(!x)return;tag[x]^=1;swap(ls,rs);}
void push_down(int x){if(tag[x]){tag[x]=0;make_tag(ls);make_tag(rs);}}
bool get(int x){return x==ch[fa[x]][1];}
bool isroot(int x){return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];}
void update(int x){if(!isroot(x))update(fa[x]);push_down(x);}
void rotate(int x){
int y=fa[x],z=fa[y],op=get(x)^1;
if(!isroot(y))ch[z][get(y)]=x;
ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
update(x);
for(int y=fa[x];!isroot(x);y=fa[x]){
if(!isroot(y))rotate(get(y)==get(x)?y:x);
rotate(x);
}
}
void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x);siz2[x]+=siz[ch[x][1]]-siz[y];
ch[x][1]=y;push_up(x);
}
}
int findroot(int x){access(x);splay(x);while(ls)push_down(x),x=ls;splay(x);return x;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
void link(int x,int y){makeroot(x);makeroot(y);fa[x]=y;siz2[y]+=siz[x];}
int solve(int x){
int lsum=0,rsum=0,sum=siz[x]>>1,u=1e9,curl,curr;
while(x){
push_down(x);
curl=lsum+siz[ls];curr=rsum+siz[rs];
if(curl<=sum&&curr<=sum)u=min(u,x);
if(curl<curr)lsum+=siz[ls]+siz2[x]+1,x=rs;
else rsum+=siz[rs]+siz2[x]+1,x=ls;
}
splay(u);return u;
}
#undef ls
#undef rs
int main(){
scanf("%d%d",&n,&m);S.init(n);
for(int i=1;i<=n;i++)ans^=i;
while(m--){
scanf("%s",op);
if(op[0]=='A'){
int x,y;scanf("%d%d",&x,&y);
link(x,y);x=S.find(x);y=S.find(y);
split(x,y);int g=solve(y);
S.fa[x]=S.fa[y]=S.fa[g]=g;
ans^=x^y^g;
}
if(op[0]=='Q'){int x;scanf("%d",&x);printf("%d\n",S.find(x));}
if(op[0]=='X')printf("%d\n",ans);
}
return 0;
}
Solution Set - LCT的更多相关文章
- 题解【bzoj2002 [Hnoi2010]Bounce 弹飞绵羊】
Description 给 \(n\) 个点以及它们的弹力系数 \(k_i\) ,含义为 可以弹到 \(i + k_i\) 的位置. 支持两个东西,修改一个点的弹力系数:求一个点要弹多少次弹出 \(n ...
- Ural Sport Programming Championship 2015
Ural Sport Programming Championship 2015 A - The First Day at School 题目描述:给出课程安排,打印一个课程表. solution 暴 ...
- BZOJ4551 - [TJOI2016]树
Portal Description 给出一棵\(n(n\leq10^5)\)个点的以\(1\)为根的有根树,进行\(Q(Q\leq10^5)\)次操作: 标记一个点\(x\). 询问\(x\)的祖先 ...
- [BZOJ1050] [HAOI2006] 旅行comf (Kruskal, LCT)
Description 给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000).给你两个顶点S和T,求一条路径,使得路径上最大 ...
- [BZOJ1036] [ZJOI2008] 树的统计Count (LCT)
Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. Q ...
- [CodeVS2370] 小机房的树 (LCA, 树链剖分, LCT)
Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花 ...
- [BZOJ2002] [Hnoi2010] Bounce 弹飞绵羊 (LCT)
Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置 ...
- [BZOJ2049] [SDOI2008] Cave 洞穴勘测 (LCT)
Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好 ...
- 72【leetcode】经典算法- Lowest Common Ancestor of a Binary Search Tree(lct of bst)
题目描述: 一个二叉搜索树,给定两个节点a,b,求最小的公共祖先 _______6______ / \ ___2__ ___8__ / \ / \ 0 _4 7 9 / \ 3 5 例如: 2,8 - ...
- 3754. 【NOI2014】魔法森林(LCT)
Problem 给定一个\(n\)个结点,\(m\)条边的的无向图,每条边有两个权值\(ai,bi\). 现在从\(1\)出发,要到达\(n\),每次只能沿着\(ai\le A\)且\(bi\le B ...
随机推荐
- 终于来了!FastGPT 正式兼容 GPT 应用
终于来了!FastGPT 正式兼容 GPT 应用 FastGPT V4.7 正式加入了工具调用功能,可以兼容 GPTs 的 Actions.这意味着,你可以直接导入兼容 GPTs 的 Agent 工具 ...
- Python 潮流周刊第 44 期(摘要)+ 赠书 5 本《明解Python算法与数据结构》
本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...
- 第十三届蓝桥杯大赛软件赛省赛【Java 大学B 组】试题D: 最少刷题数
1 import java.util.ArrayList; 2 import java.util.Scanner; 3 4 public class Main { 5 public static vo ...
- #线段树、构造#A 或位运算
题目 一个长度为\(n\)的非负整数序列, 需要满足\(m\)个区间或值为阈值的限制条件 现在要构造一个这样的序列,不存在输出No 分析 线段树支持区间与,但查询区间或,下传标记,那就很好做了 代码 ...
- C# 循环与条件语句详解
C# Switch 语句 使用 switch 语句选择要执行的多个代码块中的一个. 示例: switch(expression) { case x: // 代码块 break; case y: // ...
- C 语言运算符详解
C 语言中的运算符 运算符用于对变量和值进行操作. 在下面的示例中,我们使用 + 运算符将两个值相加: int myNum = 100 + 50; 虽然 + 运算符通常用于将两个值相加,就像上面的示例 ...
- 华为终端云服务牵手Likee,助力其用户与变现双增长
如今,社交媒体越来越深入人们的生活,改变了人们沟通方式的同时,也塑造着全新的人际关系和品牌形象.为了迎合用户多样化的需求和提升用户体验, 社交媒体行业的新老企业不断追逐着新技术和新功能.据调查机构Da ...
- 编译安装cmake,linux编译安装cmake
cmake官网:https://cmake.org/ cmake官网下载地址:https://cmake.org/download/ 现在Linux版本最新版是:cmake-3.28.0-rc5.ta ...
- MogDB/openGauss中merge的语法解析
MogDB/openGauss 中 merge 的语法解析 近期了解学习了 MogDB/openGauss 中 merge 的使用,merge 语法是根据源表对目标表进行匹配查询,匹配成功时更新,不成 ...
- 什么是coredump
什么是 coredump 介绍 在 Linux 开发中,我们经常听到程序员说我的程序 core 掉了,通常出现这类的问题是低级 bug 中的内存访问越界.使用空指针.堆栈溢出等情况.使程序运行过程中异 ...