鉴于最近写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

SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的路径,接着通过信息化的控制中心通知路径上的水管进入准备送水状态,等到路径上每一条水管都准备好了,供水公司就可以开始送水了。嘟嘟一次只能处理一项送水任务,等到当前的送水任务完成了,才能处理下一项。
在处理每项送水任务之前,路径上的水管都要进行一系列的准备操作,如清洗、消毒等等。嘟嘟在控制中心一声令下,这些水管的准备操作同时开始,但由于各条管道的长度、内径不同,进行准备操作需要的时间可能不同。供水公司总是希望嘟嘟能找到这样一条送水路径,路径上的所有管道全都准备就绪所需要的时间尽量短。嘟嘟希望你能帮助他完成这样的一个选择路径的系统,以满足供水公司的要求。另外,由于MY市的水管年代久远,一些水管会不时出现故障导致不能使用,你的程序必须考虑到这一点。
不妨将MY市的水管网络看作一幅简单无向图(即没有自环或重边):水管是图中的边,水管的连接处为图中的结点。

Input

输入文件第一行为3个整数:N, M, Q分别表示管道连接处(结点)的数目、目前水管(无向边)的数目,以及你的程序需要处理的任务数目(包括寻找一条满足要求的路径和接受某条水管坏掉的事实)。
以下M行,每行3个整数x, y和t,描述一条对应的水管。x和y表示水管两端结点的编号,t表示准备送水所需要的时间。我们不妨为结点从1至N编号,这样所有的x和y都在范围[1, N]内。
以下Q行,每行描述一项任务。其中第一个整数为k:若k=1则后跟两个整数A和B,表示你需要为供水公司寻找一条满足要求的从A到B的水管路径;若k=2,则后跟两个整数x和y,表示直接连接x和y的水管宣布报废(保证合法,即在此之前直接连接x和y尚未报废的水管一定存在)。

Output

按顺序对应输入文件中每一项k=1的任务,你需要输出一个数字和一个回车/换行符。该数字表示:你寻找到的水管路径中所有管道全都完成准备工作所需要的时间(当然要求最短)。
将狼踩尽 神犇的题解

题意:给出一个无向图,边有权值。定义一条路径的长度为该路径所有边的最大值。两种操作:(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 入门相关推荐

  1. 15行代码AC——Link/Cut Tree CodeForces - 614A(爆long long处理+快速幂讲解)

    励志用少的代码做高效表达 Problem describe Programmer Rostislav got seriously interested in the Link/Cut Tree dat ...

  2. 模板:Link Cut Tree(LCT)

    文章目录 前言 解析 原理 rotate(x) splay(x) access(x) findroot(x) makeroot(x) split(x,y) link(x,y) cut(x,y) pus ...

  3. Link Cut Tree 学习笔记

    Link Cut Tree 学习笔记 说在前边 最近补 CF 碰见一道 LCT ,就打算学习一下这个东西...顺便复习一下 splay. 具体算法及实现 参考了FlashHu, Candy? P369 ...

  4. Link/Cut Tree学习笔记

    最近正是实验课的高峰期,我数了一下,除了毛概没有实验课,其他的课都有实验课...不过好在这些实验都不是很难.我尽力挤出时间用来刷题. 简介 Link/Cut Tree和树链剖分很相似,二者处理的问题也 ...

  5. Link Cut Tree详解

    Link Cut Tree ==Warning:千万不要跳读== 参考博客:https://www.cnblogs.com/flashhu/p/8324551.html 什么是动态树? 动态树问题, ...

  6. luogu P3690 【模板】Link Cut Tree (动态树)

    嘟嘟嘟 LCT竟然看了整整一天,但好歹是看懂了. 教程这里不写,强烈推荐 闪狐大佬的博客 . 但是还是有几句想说的. 1.尽管LCT和splay很像,但是有一些细节还是不一样的.首先是rotate,我 ...

  7. Link Cut Tree学习笔记

    捋一下思路 模板题:https://www.luogu.org/problemnew/show/P3690 推荐LCT的教程,个人认为很详细,本文做了部分引用:https://www.luogu.or ...

  8. 洛谷 - P3690 【模板】Link Cut Tree (动态树)(LCT模板)

    题目链接:点击查看 题目大意:给出 n 个带权节点,需要执行 m 次操作,每次操作分为四种类型: 0 x y 代表询问从 x 到 y 的路径上的点的权值的 xor 和.保证 x 到 y 是联通的. 1 ...

  9. P3690-[模板]Link Cut Tree(动态树)【Splay】

    正题 题目链接:https://www.luogu.org/problem/P3690 题目大意 nnn个点mmm个操作,要求支持 询问路径异或和 连接一条边(若x,yx,yx,y没联通) 删除一条边 ...

最新文章

  1. mongodb 备份和恢复
  2. python电脑配置大概要多少钱-学python最电脑配置有要求么
  3. SAP ABAP SQL查询分析器
  4. 练习系列 - 5、求子数组的最大和
  5. php js urlencode,JavaScript版本的UrlEncode和UrlDecode函数实现
  6. [css] css中的选择器、属性、属性值区分大小写吗?
  7. linux内存布局的内核实现--用户空间的映射方式
  8. mysql strchr_PHP字符串函数之 strstr stristr
  9. 使用模板实现asp代码和页面分离_asp技巧
  10. Android 安全 (一)
  11. cmd命令行开启windows远程桌面服务
  12. 知乎引流实操:日吸200精准粉丝玩法分享
  13. 让 orangepi 用上Btsync(资源分享工具)好资源不怕和谐!
  14. ViewPage动态删除页面
  15. java读写yml文件
  16. 【机器学习】10:朴素贝叶斯做文本分类
  17. 优盘格式化为FAT64
  18. ios11更新提示信任_iPhone手机iOS11怎么设置信任软件
  19. Vmware 15 关闭Hyper-V后,仍有VMware不兼容报错 写入文件时出错,请确认您有访问该目录的权限 -_-
  20. 【路径规划】基于灰狼算法实现机器人栅格地图路径规划matlab源码

热门文章

  1. pmp知识点整理和答题技巧
  2. 课后实践2:以抖音为例使用以尼尔森十大可用性原则体验产品
  3. pyqtgraph:GLSurfacePlotItem如何在三维地形表面自定义颜色分布(读取图片给三维平面分区域着色)
  4. 如何修改Word文件里面的段落背影颜色
  5. 如何快速学会3dmax建模?这里有4个套路|小白建模攻略
  6. 日记侠:撰写吸粉文案的5大步骤
  7. 关系数据库设计及数据库标准语言SQL(多表查询)
  8. php已知公鸡每只5元,公鸡3元一只,母鸡5元1只,小鸡3只1元,一百元共买100只鸡,请用php编写程序计算机多少只公鸡、母鸡和小鸡,请将代码和结果截图上传平台。...
  9. 思迈特软件Smartbi的特色功能有哪些?
  10. 机器学习之人脸识别人像采集