bzoj1036 [ZJOI2008]树的统计Count——LCT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1036
LCT水题!
然而没有1A(咬牙)!
注意值有负数,所以取 max 的话要把作为“哨兵”的 0号点 的 max 赋成很小的值才行。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const maxn=30005; int n,m,fa[maxn],c[maxn][3],rev[maxn],mx[maxn],sum[maxn],w[maxn],sta[maxn],a[maxn],b[maxn],top; bool isroot(int x){return c[fa[x]][0]!=x && c[fa[x]][1]!=x;} void pushup(int x) { int ls=c[x][0],rs=c[x][1]; sum[x]=sum[ls]+sum[rs]+w[x]; mx[x]=x; if(w[mx[x]]<w[mx[ls]])mx[x]=mx[ls]; if(w[mx[x]]<w[mx[rs]])mx[x]=mx[rs]; } void reverse(int x) { if(rev[x]) { rev[c[x][0]]^=1; rev[c[x][1]]^=1; rev[x]=0; swap(c[x][0],c[x][1]); } } void rotate(int x) { int y=fa[x],z=fa[y],d=(c[y][1]==x); if(!isroot(y))c[z][c[z][1]==y]=x; fa[x]=z; fa[y]=x; fa[c[x][!d]]=y; c[y][d]=c[x][!d]; c[x][!d]=y; pushup(y); pushup(x); } void splay(int x) { sta[top=1]=x; for(int i=x;!isroot(i);i=fa[i])sta[++top]=fa[i]; for(;top;top--)reverse(sta[top]); for(;!isroot(x);rotate(x)) { int y=fa[x],z=fa[y]; if(isroot(y))continue; ((c[y][0]==x)^(c[z][0]==y))?rotate(x):rotate(y); } } void access(int x) { for(int t=0;x;splay(x),c[x][1]=t,pushup(x),t=x,x=fa[x]); } void makeroot(int x) { access(x); splay(x); rev[x]^=1; } void link(int x,int y) { makeroot(x); fa[x]=y; } void query(int x,int y) { makeroot(x); access(y); splay(y); } void cut(int x,int y) { query(x,y); fa[x]=0; c[y][0]=0; } void change(int u,int t) { makeroot(u); w[u]=t; pushup(u);//makeroot } int main() { scanf("%d",&n); w[mx[0]]=-30005;//! for(int i=1,x,y;i<n;i++)scanf("%d%d",&a[i],&b[i]); for(int i=1;i<=n;i++)scanf("%d",&w[i]); for(int i=1;i<n;i++)link(a[i],b[i]); scanf("%d",&m); char ch[10]; for(int i=1,x,y;i<=m;i++) { scanf("%s",&ch); scanf("%d%d",&x,&y); if(ch[0]=='C')change(x,y); else { query(x,y); if(ch[1]=='M')printf("%d\n",w[mx[y]]); if(ch[1]=='S')printf("%d\n",sum[y]); } } return 0; }