BZOJ 2157 旅游(动态树)
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2157
【题目大意】
支持修改边,链上查询最大值最小值总和,以及链上求相反数
【题解】
我们将边转化成点,直接用LCT可以处理以上操作
【代码】
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=200010; int n; const int INF=~0U>>1; namespace Link_Cut_Tree{ int f[N],son[N][2],tmp[N],tag[N],val[N],sum[N],mx[N],mn[N]; bool rev[N]; void Initialize(){ memset(f,0,sizeof(f)); memset(son,0,sizeof(son)); memset(val,0,sizeof(val)); memset(rev,0,sizeof(rev)); memset(sum,0,sizeof(sum)); memset(tag,0,sizeof(tag)); } void reverse(int x){ sum[x]=-sum[x]; val[x]=-val[x]; swap(mn[x],mx[x]); mn[x]=-mn[x],mx[x]=-mx[x]; tag[x]^=1; } bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;} void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;} void pb(int x){ if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0; if(tag[x]){ tag[x]=0; if(son[x][0])reverse(son[x][0]); if(son[x][1])reverse(son[x][1]); } } void up(int x){ sum[x]=val[x]+sum[son[x][0]]+sum[son[x][1]]; mx[x]=max(mx[son[x][0]],mx[son[x][1]]); mn[x]=min(mn[son[x][0]],mn[son[x][1]]); if(x>n)mx[x]=max(mx[x],val[x]); if(x>n)mn[x]=min(mn[x],val[x]); } void rotate(int x){ int y=f[x],w=son[y][1]==x; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y]){ int z=f[y]; if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x; }f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y); } void splay(int x){ int s=1,i=x,y;tmp[1]=i; while(!isroot(i))tmp[++s]=i=f[i]; while(s)pb(tmp[s--]); while(!isroot(x)){ y=f[x]; if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);} rotate(x); }up(x); } void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);} // 查询x所在的树的根 int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;} // 使x成为根 void makeroot(int x){access(x);splay(x);rev1(x);} // 将x和y所属树合并 void link(int x,int y){makeroot(x);f[x]=y;access(x);} // 提取链 void split(int x,int y){makeroot(y);access(x);splay(x);} // 查询x到y的链和 int ask(int x,int y){split(x,y);return sum[x];} // 查询x到y的链最大值 int askmx(int x,int y){split(x,y);return mx[x];} // 查询x到y的链最小值 int askmn(int x,int y){split(x,y);return mn[x];} } int E[N],m; int main(){ scanf("%d",&n); using namespace Link_Cut_Tree; Initialize(); for(int i=0;i<=n;i++)mx[i]=-INF,mn[i]=INF; int id=n; for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); E[i]=++id; link(x+1,id); link(y+1,id); val[id]=sum[id]=mx[id]=mn[id]=z; }char op[10]; scanf("%d",&m); while(m--){ scanf("%s",op); int x,y; scanf("%d%d",&x,&y); if(op[0]=='N'){split(x+1,y+1);reverse(x+1);} else if(op[0]=='S'){printf("%d\n",ask(x+1,y+1));} else if(op[1]=='I'){printf("%d\n",askmn(x+1,y+1));} else if(op[1]=='A'){printf("%d\n",askmx(x+1,y+1));} else{makeroot(E[x]);val[E[x]]=y;} }return 0; }
愿你出走半生,归来仍是少年