link cut tree 入门
鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构。
link cut tree:研究popoqqq那个神ppt。
bzoj1036:维护access操作就可以了。
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<queue>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
#define qwq(x) for(edge *o=head[x];o;o=o->next)
int read(){ int x=0,f=1;char c=getchar(); while(!isdigit(c)){ if(c=='-') f=-1;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x*f;
}
const int nmax=3e4+5;
const int inf=0x7f7f7f7f;
struct edge{ int to;edge *next;
};
edge es[nmax<<1],*pt=es,*head[nmax];
void add(int u,int v){ pt->to=v;pt->next=head[u];head[u]=pt++; pt->to=u;pt->next=head[v];head[v]=pt++;
}
int n,m,fa[nmax],c[nmax][2],sm[nmax],mx[nmax],q[nmax],w[nmax];bool vis[nmax];
void bfs(){ int l=1,r=1,x;q[r]=1;vis[1]=1; while(l<=r){ x=q[l++]; qwq(x) if(!vis[o->to]) fa[o->to]=x,q[++r]=o->to,vis[o->to]=1; }
}
bool pdrt(int x){ return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
void update(int x){ int l=c[x][0],r=c[x][1]; sm[x]=sm[l]+sm[r]+w[x];mx[x]=max(w[x],max(mx[l],mx[r]));
}
void rotate(int x){ int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; if(!pdrt(y)) if(c[z][0]==y) c[z][0]=x;else c[z][1]=x; fa[x]=z;fa[y]=x;fa[c[x][r]]=y; c[y][l]=c[x][r];c[x][r]=y; update(y);update(x);
}
void splay(int x){ //把一个点伸展到它所在的重链的根。 int y,z;//fa[x]=y表示以x为根的splay树的父亲是y,但是y的两个儿子(c[y][0]和c[y][1])中没有一个是x while(!pdrt(x)){ y=fa[x];z=fa[y]; if(!pdrt(y)) if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y); rotate(x); }
}
int access(int x){ int t=0; while(x) splay(x),c[x][1]=t,t=x,update(x),x=fa[x]; return t; //考虑点u,v。假设先access(u)了,那么access(lca(u,v))时lca(u,v)是原splay的根节点, //左边的是深度比它小的点,即是lca(u,v)到根的链。 说明access的操作是正确的。
}
void qsum(int u,int v){ access(u);int lca=access(v);splay(u); if(lca==u) printf("%d\n",w[u]+sm[c[lca][1]]); else printf("%d\n",w[lca]+sm[c[lca][1]]+sm[u]);
}
void qmax(int u,int v){ access(u);int lca=access(v);splay(u); if(lca==u) printf("%d\n",max(w[u],mx[c[lca][1]])); else printf("%d\n",max(w[lca],max(mx[c[lca][1]],mx[u])));
}
int main(){ n=read();int u,v,d;mx[0]=-inf; rep(i,1,n-1) u=read(),v=read(),add(u,v); rep(i,1,n) sm[i]=mx[i]=w[i]=read();bfs(); m=read();char ch[11]; rep(i,1,m){ scanf("%s",ch);u=read(),v=read(); if(ch[1]=='H') splay(u),w[u]=v,update(u); else if(ch[1]=='S') qsum(u,v); else qmax(u,v); } return 0;
}
bzoj2049:link cut tree 模版题。
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
#define qwq(x) for(edge *o=head[x];o;o=o->next)
int read(){ int x=0,f=1;char c=getchar(); while(!isdigit(c)){ if(c=='-') f=-1;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x*f;
}
const int nmax=1e4+5;
int n,m,fa[nmax],c[nmax][2],st[nmax],rev[nmax];
bool pdrt(int x){ return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
void pushdown(int x){ if(rev[x]){ int l=c[x][0],r=c[x][1]; rev[x]^=1;rev[l]^=1;rev[r]^=1; swap(c[x][0],c[x][1]); }
}
void rotate(int x){ int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; if(!pdrt(y)) if(c[z][0]==y) c[z][0]=x;else c[z][1]=x; fa[x]=z;fa[y]=x;fa[c[x][r]]=y; c[y][l]=c[x][r];c[x][r]=y;
}
void splay(int x){ int top=0,y,z;st[++top]=x; for(int i=x;!pdrt(i);i=fa[i]) st[++top]=fa[i]; dwn(i,top,1) pushdown(st[i]); while(!pdrt(x)){ y=fa[x];z=fa[y]; if(!pdrt(y)) if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y); rotate(x); }
}
void access(int x){ int t=0; while(x) splay(x),c[x][1]=t,t=x,x=fa[x];
}
void rever(int x){ access(x);splay(x);rev[x]^=1;
}
void link(int x,int y){ rever(x);fa[x]=y;
}
void cut(int x,int y){ rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
}
int find(int x){ access(x);splay(x); int y=x;while(c[y][0]) y=c[y][0]; return y;
}
int main(){ n=read(),m=read();int x,y;char ch[11]; rep(i,1,m){ scanf("%s",ch);x=read(),y=read(); if(ch[0]=='C') link(x,y); else if(ch[0]=='D') cut(x,y); else { if(find(x)==find(y)) puts("Yes"); else puts("No"); } } return 0;
}
我这二逼智商。。。真的够了。。。。
upd9.27 重新理解了两次link cut tree 然后打起代码来顺多了。。。
bzoj2002:还是基本的操作
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
int read(){int x=0;char c=getchar();while(!isdigit(c)) c=getchar();while(isdigit(c)) x=x*10+c-'0',c=getchar();return x;
}
const int nmax=2e5+5;
const int inf=0x7f7f7f7f;
int fa[nmax],c[nmax][2],sz[nmax],q[nmax],nxt[nmax];
bool rev[nmax];
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
void pushup(int x){sz[x]=sz[c[x][0]]+sz[c[x][1]]+1;
}
void pushdown(int x){if(rev[x]){int l=c[x][0],r=c[x][1];rev[x]=0;rev[l]^=1;rev[r]^=1;swap(c[x][0],c[x][1]);}
}
void rotate(int x){int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;if(!isroot(y)) c[z][c[z][1]==y]=x;fa[x]=z;fa[y]=x;fa[c[x][r]]=y;c[y][l]=c[x][r];c[x][r]=y;pushup(y);pushup(x);
}
void splay(int x){int cnt=0,y,z;q[++cnt]=x;for(int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];dwn(i,cnt,1) pushdown(q[i]);while(!isroot(x)){y=fa[x],z=fa[y];if(!isroot(y)){if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y);}rotate(x);}
}
void access(int x){int t=0;while(x) splay(x),c[x][1]=t,t=x,x=fa[x]; //这里应该是要pushup(x)的。但是为什么不加也能A啊TAT
}
void rever(int x){access(x),splay(x),rev[x]^=1;
}
void link(int x,int y){rever(x);fa[x]=y;
}
void cut(int x,int y){rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
}
int main(){int n=read(),u,v,d;rep(i,1,n){u=read();fa[i]=min(n+1,i+u);sz[i]=1;nxt[i]=fa[i];}sz[n+1]=1;int m=read();while(m--){u=read();if(u==1){rever(n+1);v=read()+1;access(v);splay(v);printf("%d\n",sz[c[v][0]]);}else{v=read()+1;d=read();u=min(n+1,v+d);cut(v,nxt[v]);link(v,u);nxt[v]=u;}}return 0;
}
/*
4
1 2 1 1
3
1 1
2 1 1
1 1
*/
bzoj3282:还是基本操作
因为pushup我放在了x=fa[x]后面调了一节晚自修。
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
int read(){int x=0;char c=getchar();while(!isdigit(c)) c=getchar();while(isdigit(c)) x=x*10+c-'0',c=getchar();return x;
}
const int nmax=3e5+5;
const int inf=0x7f7f7f7f;
int fa[nmax],c[nmax][2],sz[nmax],w[nmax],q[nmax];
bool rev[nmax];
void pushup(int x){sz[x]=w[x]^sz[c[x][0]]^sz[c[x][1]];
}
void pushdown(int x){if(rev[x]){int l=c[x][0],r=c[x][1];rev[x]=0;rev[l]^=1;rev[r]^=1;swap(c[x][0],c[x][1]);}
}
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
void rotate(int x){int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;if(!isroot(y)) c[z][c[z][1]==y]=x;fa[x]=z;fa[y]=x;fa[c[x][r]]=y;c[y][l]=c[x][r];c[x][r]=y;pushup(y);pushup(x);
}
void splay(int x){int cnt=0,y,z;q[++cnt]=x;for(int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];dwn(i,cnt,1) pushdown(q[i]);while(!isroot(x)){y=fa[x];z=fa[y];if(!isroot(y)){if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y);}rotate(x);}
}
void access(int x){int t=0;while(x) splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x];
}
//因为pushup我放在了x=fa[x]后面调了一节晚自修。
void rever(int x){access(x),splay(x),rev[x]^=1;
}
void link(int x,int y){rever(x);fa[x]=y;
}
void cut(int x,int y){rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
}
int find(int x){access(x);splay(x);while(c[x][0]) x=c[x][0];return x;
}
int main(){int n=read(),m=read(),u,x,y;rep(i,1,n) sz[i]=w[i]=read();while(m--){u=read(),x=read(),y=read();if(u==0) {rever(x);access(y),splay(y);printf("%d\n",sz[y]);}else if(u==1) {if(find(x)!=find(y)) link(x,y);}else if(u==2) {if(find(x)==find(y)) cut(x,y);}else {access(x),splay(x),w[x]=y,pushup(x);}}return 0;
}
bzoj2843&1180:还是基本操作
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(register int i=s;i<=t;i++)
#define dwn(i,s,t) for(register int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
#define lc c[x][0]
#define rc c[x][1]
int read(){int x=0;char c=getchar();while(!isdigit(c)) c=getchar();while(isdigit(c)) x=x*10+c-'0',c=getchar();return x;
}
const int nmax=3e4+5;
const int inf=0x7f7f7f7f;
int fa[nmax],c[nmax][2],sm[nmax],w[nmax],q[nmax];
bool rev[nmax];
bool isroot(int x){int t=x;x=fa[x];return lc!=t&&rc!=t;
}
void pushup(int x){sm[x]=w[x]+sm[lc]+sm[rc];
}
void pushdown(int x){if(rev[x]){rev[x]=0;rev[lc]^=1;rev[rc]^=1;swap(lc,rc);}
}
void rotate(int x){int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;if(!isroot(y)) c[z][c[z][1]==y]=x;fa[x]=z;fa[y]=x;fa[c[x][r]]=y;c[y][l]=c[x][r];c[x][r]=y;pushup(y);pushup(x);
}
void splay(int x){int cnt=0,y,z;q[++cnt]=x;for(register int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];dwn(i,cnt,1) pushdown(q[i]);while(!isroot(x)){y=fa[x];z=fa[y];if(!isroot(y)) {if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y);}rotate(x);}
}
void access(int x){int t=0;while(x) splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x];
}
void rever(int x){access(x);splay(x);rev[x]^=1;
}
void link(int x,int y){rever(x);fa[x]=y;if(!(x&233)) splay(x);//都不splayx或者都splayx会比较慢。。。
}
void cut(int x,int y){rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
}
int find(int x){access(x);splay(x);while(c[x][0]) x=c[x][0];return x;
}
int main(){int n=read();rep(i,1,n) w[i]=sm[i]=read();int m=read(),u,v,d;char s[15];while(m--){scanf("%s",s);u=read(),v=read();if(s[0]=='b') {if(find(u)!=find(v)) link(u,v),puts("yes");else puts("no");}else if(s[0]=='e'){if(find(u)!=find(v)) puts("impossible");else rever(u),access(v),splay(v),printf("%d\n",sm[v]);}else{splay(u);w[u]=v;pushup(u);}}return 0;
}
bzoj3669:
3669: [Noi2014]魔法森林
Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 2156 Solved: 1310
[Submit][Status][Discuss]
Description
为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M。初始时小E同学在号节点1,隐士则住在号节点N。小E需要通过这一片魔法森林,才能够拜访到隐士。
魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。幸运的是,在号节点住着两种守护精灵:A型守护精灵与B型守护精灵。小E可以借助它们的力量,达到自己的目的。
只要小E带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型守护精灵个数不少于Ai,且B型守护精灵个数不少于Bi,这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击,他才能成功找到隐士。
由于携带守护精灵是一件非常麻烦的事,小E想要知道,要能够成功拜访到隐士,最少需要携带守护精灵的总个数。守护精灵的总个数为A型守护精灵的个数与B型守护精灵的个数之和。
Input
第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含4个正整数Xi,Yi,Ai,Bi,描述第i条无向边。其中Xi与Yi为该边两个端点的标号,Ai与Bi的含义如题所述。 注意数据中可能包含重边与自环。
Output
输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出“-1”(不含引号)。
WerKeyTom_FTD 神犇的题解:
我们尝试枚举路径的最大a值,那么我们只需按照a排序按顺序插入,维护1到n的b最大值即可。
用并查集维护连通性。当加入j到k这条边时如果形成环,则删除环上的最大值。
我们用动态树来进行维护。
为了实现更易,将每条边看做一个点,例如第i条边两个端点是j与k,那么将i+n与j、k相连,权值放在代表边的点上。
然后莫名其妙的空间开小了居然是TLE重新打一遍的过程中突然想到nmax开小了TAT
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x;
}
const int nmax=2e5+5;
const int maxn=1e5+5;
const int inf=0x7f7f7f7f;
int fa[nmax],c[nmax][2],mx[nmax],q[nmax],p[nmax],w[nmax];
bool rev[nmax];
struct edge{ int u,v,a,b; bool operator<(const edge &rhs)const{ return a<rhs.a;}
};
edge es[maxn];
bool isroot(int x){ return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
void pushup(int x){ int l=c[x][0],r=c[x][1]; mx[x]=x; if(w[mx[x]]<w[mx[l]]) mx[x]=mx[l]; if(w[mx[x]]<w[mx[r]]) mx[x]=mx[r];
}
void pushdown(int x){ if(rev[x]){ rev[x]=0;rev[c[x][0]]^=1;rev[c[x][1]]^=1; swap(c[x][0],c[x][1]); }
}
void rotate(int x){ int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; if(!isroot(y)) c[z][c[z][1]==y]=x; fa[x]=z;fa[y]=x;fa[c[x][r]]=y; c[y][l]=c[x][r];c[x][r]=y; pushup(y);pushup(x);
}
void splay(int x){ int cnt=0,y,z;q[++cnt]=x; for(register int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i]; dwn(i,cnt,1) pushdown(q[i]); while(!isroot(x)){ y=fa[x];z=fa[y]; if(!isroot(y)){ if(c[y][0]==x^c[z][0]==y) rotate(x); else rotate(y); } rotate(x); }
}
void access(int x){ int t=0; while(x) splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x];
}
void rever(int x){ access(x);splay(x);rev[x]^=1;
}
void link(int x,int y){ rever(x);fa[x]=y;if(x&233) splay(x);
}
void cut(int x,int y){ rever(x);access(y);splay(y);c[y][0]=fa[x]=0;pushup(y);
}
int find(int x){ return p[x]==x?x:p[x]=find(p[x]);
}
int query(int x,int y){ rever(x);access(y),splay(y);return mx[y];
}
void mins(int &a,int b){ if(a>b) a=b;
}
int main(){ int n=read(),m=read(),u,v,d,tmp,temp,ta,tb; rep(i,1,m) es[i].u=read(),es[i].v=read(),es[i].a=read(),es[i].b=read(); sort(es+1,es+m+1); int ans=inf;rep(i,1,n) p[i]=i; rep(i,1,m){ u=es[i].u,v=es[i].v;ta=find(u),tb=find(v); if(ta==tb){ d=query(u,v); if(w[d]>es[i].b) cut(d,es[d-n].u),cut(d,es[d-n].v); else { if(find(1)==find(n)) mins(ans,es[i].a+w[query(1,n)]); continue; } }else p[ta]=tb; w[n+i]=es[i].b;mx[n+i]=n+i; link(u,n+i),link(v,n+i); if(find(1)==find(n)) mins(ans,es[i].a+w[query(1,n)]); } printf("%d\n",ans==inf?-1:ans); return 0;
}
/*
4 5
1 2 19 1
2 3 8 12
2 4 12 15
1 3 17 8
3 4 1 17
*/
bzoj2594:
2594: [Wc2006]水管局长数据加强版
Time Limit: 25 Sec Memory Limit: 128 MB
Submit: 2600 Solved: 840
[Submit][Status][Discuss]
Description
Input
Output
题意:给出一个无向图,边有权值。定义一条路径的长度为该路径所有边的最大值。两种操作:(1)询问u到v所有路径的长度的最小值;(2)删掉某条边。
思路:
(1)将每个边也转化成一个点,比如边(1,2),转化成(1,3),(3,2)两个边;那么边权看做3的点权;1和2的点权可以看做0;
(2)反着做。首先将删掉的边都删掉,询问倒着回答,那么就成了加边。
(3)显然,路径长度就是最小生成树的最大值。因此,首先,将没有删掉的边求一次最小生成树,将最小生成树的边建立动态树。
(4)对于查询比较简单直接查就行。
(5)对于添加边(u,v),若u与v之前没有连通,则该边直接加进去就行,其实就是两个子树连在一起;否则,该边加进去之后会出现环,那么需要删掉环上的最大值的边。
然后因为p[x]习惯性的写成了fa[x]然后调了一节晚自修我TAT
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
int read(){int x=0;char c=getchar();while(!isdigit(c)) c=getchar();while(isdigit(c)) x=x*10+c-'0',c=getchar();return x;
}
const int nmax=1500005;
const int maxn=1000005;
const int inf=0x7f7f7f7f;
struct edge{int u,v,d,id,f;
};
edge es[maxn],ns[100005];
bool cmp(edge a,edge b){return a.d<b.d;
}
bool comp(edge a,edge b){return a.id<b.id;
}
bool cp(edge a,edge b){return a.u<b.u||a.u==b.u&&a.v<b.v;
}
int fa[nmax],c[nmax][2],q[nmax],mx[nmax],w[nmax],ans[nmax],p[nmax];bool rev[nmax];
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
void pushup(int x){int l=c[x][0],r=c[x][1];mx[x]=x;if(w[mx[x]]<w[mx[l]]) mx[x]=mx[l];if(w[mx[x]]<w[mx[r]]) mx[x]=mx[r];
}
void pushdown(int x){if(rev[x]){rev[x]=0;rev[c[x][0]]^=1;rev[c[x][1]]^=1;swap(c[x][0],c[x][1]);}
}
void rotate(int x){int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;if(!isroot(y)) c[z][c[z][1]==y]=x;fa[x]=z;fa[y]=x;fa[c[x][r]]=y;c[y][l]=c[x][r];c[x][r]=y;pushup(y);pushup(x);
}
void splay(int x){int cnt=0,y,z;q[++cnt]=x;for(int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];dwn(i,cnt,1) pushdown(q[i]);while(!isroot(x)){y=fa[x];z=fa[y];if(!isroot(y)){if(c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y);}rotate(x);}
}
void access(int x){int t=0;while(x) splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x];
}
void rever(int x){access(x);splay(x);rev[x]^=1;
}
void link(int x,int y){rever(x);fa[x]=y;
}
void cut(int x,int y){rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
}
int query(int x,int y){rever(x);access(y);splay(y);return mx[y];
}
int find(int x,int y,int m){int l=1,r=m,mid;while(l<=r){mid=(l+r)>>1;if(es[mid].u<x||es[mid].u==x&&es[mid].v<y) l=mid+1;else if(es[mid].u==x&&es[mid].v==y) return mid;else r=mid-1;}
}
int ff(int x){return p[x]==x?x:p[x]=ff(p[x]);
}
int main(){int n=read(),m=read(),q=read(),tmp,temp,u,v,d,ta,tb;rep(i,1,m) {es[i].u=read(),es[i].v=read(),es[i].d=read();if(es[i].u>es[i].v) swap(es[i].u,es[i].v);}sort(es+1,es+m+1,cmp);rep(i,1,m) es[i].id=i,w[n+i]=es[i].d,mx[n+i]=n+i;sort(es+1,es+m+1,cp);rep(i,1,q) {ns[i].d=read(),ns[i].u=read(),ns[i].v=read();if(ns[i].u>ns[i].v) swap(ns[i].u,ns[i].v);if(ns[i].d==2) tmp=find(ns[i].u,ns[i].v,m),es[tmp].f=1,ns[i].id=es[tmp].id;}sort(es+1,es+m+1,comp);int cnt=0;rep(i,1,n) p[i]=i;rep(i,1,m) if(!es[i].f){u=es[i].u;v=es[i].v;ta=ff(u);tb=ff(v);if(ta!=tb){p[ta]=tb;link(u,i+n);link(v,i+n);//因为这里的p习惯性的打成了fa调了一节晚自修各种中间输出就是在这里WA然后一直检查模版TAT if(++cnt==n-1) break;}}dwn(i,q,1){if(ns[i].d==1) ans[i]=w[query(ns[i].u,ns[i].v)];else{u=ns[i].u,v=ns[i].v,d=ns[i].id;tmp=query(u,v);if(es[d].d<w[tmp]) {cut(tmp,es[tmp-n].u);cut(tmp,es[tmp-n].v);link(u,d+n);link(v,d+n);}}}rep(i,1,q) if(ns[i].d==1) printf("%d\n",ans[i]);return 0;
}
转载于:https://www.cnblogs.com/fighting-to-the-end/p/5894148.html
link cut tree 入门相关推荐
- 15行代码AC——Link/Cut Tree CodeForces - 614A(爆long long处理+快速幂讲解)
励志用少的代码做高效表达 Problem describe Programmer Rostislav got seriously interested in the Link/Cut Tree dat ...
- 模板:Link Cut Tree(LCT)
文章目录 前言 解析 原理 rotate(x) splay(x) access(x) findroot(x) makeroot(x) split(x,y) link(x,y) cut(x,y) pus ...
- Link Cut Tree 学习笔记
Link Cut Tree 学习笔记 说在前边 最近补 CF 碰见一道 LCT ,就打算学习一下这个东西...顺便复习一下 splay. 具体算法及实现 参考了FlashHu, Candy? P369 ...
- Link/Cut Tree学习笔记
最近正是实验课的高峰期,我数了一下,除了毛概没有实验课,其他的课都有实验课...不过好在这些实验都不是很难.我尽力挤出时间用来刷题. 简介 Link/Cut Tree和树链剖分很相似,二者处理的问题也 ...
- Link Cut Tree详解
Link Cut Tree ==Warning:千万不要跳读== 参考博客:https://www.cnblogs.com/flashhu/p/8324551.html 什么是动态树? 动态树问题, ...
- luogu P3690 【模板】Link Cut Tree (动态树)
嘟嘟嘟 LCT竟然看了整整一天,但好歹是看懂了. 教程这里不写,强烈推荐 闪狐大佬的博客 . 但是还是有几句想说的. 1.尽管LCT和splay很像,但是有一些细节还是不一样的.首先是rotate,我 ...
- Link Cut Tree学习笔记
捋一下思路 模板题:https://www.luogu.org/problemnew/show/P3690 推荐LCT的教程,个人认为很详细,本文做了部分引用:https://www.luogu.or ...
- 洛谷 - P3690 【模板】Link Cut Tree (动态树)(LCT模板)
题目链接:点击查看 题目大意:给出 n 个带权节点,需要执行 m 次操作,每次操作分为四种类型: 0 x y 代表询问从 x 到 y 的路径上的点的权值的 xor 和.保证 x 到 y 是联通的. 1 ...
- P3690-[模板]Link Cut Tree(动态树)【Splay】
正题 题目链接:https://www.luogu.org/problem/P3690 题目大意 nnn个点mmm个操作,要求支持 询问路径异或和 连接一条边(若x,yx,yx,y没联通) 删除一条边 ...
最新文章
- mongodb 备份和恢复
- python电脑配置大概要多少钱-学python最电脑配置有要求么
- SAP ABAP SQL查询分析器
- 练习系列 - 5、求子数组的最大和
- php js urlencode,JavaScript版本的UrlEncode和UrlDecode函数实现
- [css] css中的选择器、属性、属性值区分大小写吗?
- linux内存布局的内核实现--用户空间的映射方式
- mysql strchr_PHP字符串函数之 strstr stristr
- 使用模板实现asp代码和页面分离_asp技巧
- Android 安全 (一)
- cmd命令行开启windows远程桌面服务
- 知乎引流实操:日吸200精准粉丝玩法分享
- 让 orangepi 用上Btsync(资源分享工具)好资源不怕和谐!
- ViewPage动态删除页面
- java读写yml文件
- 【机器学习】10:朴素贝叶斯做文本分类
- 优盘格式化为FAT64
- ios11更新提示信任_iPhone手机iOS11怎么设置信任软件
- Vmware 15 关闭Hyper-V后,仍有VMware不兼容报错 写入文件时出错,请确认您有访问该目录的权限 -_-
- 【路径规划】基于灰狼算法实现机器人栅格地图路径规划matlab源码
热门文章
- pmp知识点整理和答题技巧
- 课后实践2:以抖音为例使用以尼尔森十大可用性原则体验产品
- pyqtgraph:GLSurfacePlotItem如何在三维地形表面自定义颜色分布(读取图片给三维平面分区域着色)
- 如何修改Word文件里面的段落背影颜色
- 如何快速学会3dmax建模?这里有4个套路|小白建模攻略
- 日记侠:撰写吸粉文案的5大步骤
- 关系数据库设计及数据库标准语言SQL(多表查询)
- php已知公鸡每只5元,公鸡3元一只,母鸡5元1只,小鸡3只1元,一百元共买100只鸡,请用php编写程序计算机多少只公鸡、母鸡和小鸡,请将代码和结果截图上传平台。...
- 思迈特软件Smartbi的特色功能有哪些?
- 机器学习之人脸识别人像采集