rt
就过了一个点,其他点都应该输出负数,而我的输出为0,通过某神奇方法弄了一组数据,然后一直都是有一个点为 0 ,看了第一页的解改了改还是一直错,实在改不出来了。
下面是代码
/*
* @Author: smyslenny
* @Date: 2021.09.07
* @Title: P2590 [ZJOI2008]树的统计
* @Main idea:LCT
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)
#define lson(p) tree[(p)].ch[0]
#define rson(p) tree[(p)].ch[1]
using namespace std;
const int mod=998244353;
const int M=5e5+5;
int n,m,u[M],v[M];
int read()
{
int x=0,y=1;
char c=getchar();
while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
return y?x:-x;
}
struct tr{
int ch[3],sum,laz,Max,val;
}tree[M<<2];
void push_up(int p)
{
tree[p].sum=tree[lson(p)].sum+tree[rson(p)].sum+tree[p].val;
tree[p].Max=max(tree[lson(p)].Max,max(tree[rson(p)].Max,tree[p].val));
}
/*
void ff(int p)
{
swap(lson(p),rson(p));
tree[p].laz^=1;
}
*/
void push_down(int p)
{
if(!tree[p].laz) return;
if(lson(p)) tree[lson(p)].laz^=1;
if(rson(p)) tree[rson(p)].laz^=1;
swap(lson(p),rson(p));
tree[p].laz=0;
}
int f[M];
bool isroot(int x)//判断当前点是否是实链的根节点
{//当前点是根节点因为这它认父亲,父亲不认儿子
return lson(f[x])!=x && rson(f[x])!=x;
}
void rotate(int x,int op)
{
int y=f[x];
if(!isroot(y))
tree[f[y]].ch[rson(f[y])==y]=x;//原先父亲节点与其父亲节点的边断开,连上现在的这个点
f[x]=f[y];//儿子节点的爸爸换成爷爷
if(tree[x].ch[op])//儿子节点op儿子有的话,改变他的父亲为父亲
f[tree[x].ch[op]]=y;
tree[y].ch[!op]=tree[x].ch[op];//父亲的儿子变成儿子的儿子
f[y]=x;//父亲的父亲变成儿子
tree[x].ch[op]=y;//儿子的对应儿子变成父亲
push_up(y);
//注:注释里的父亲,儿子,爷爷,都表示没变化之前的称谓
}
int sta[M],top;//为了将懒惰标记一气儿下传
void splay(int x)
{
top=0;
sta[++top]=x;
for(int i=x;!isroot(i);i=f[i]) sta[++top]=f[i];
while(top) push_down(sta[top--]);//splay之前先将要旋转的链上的懒惰标记全部下穿,免去了边旋转边下传的麻烦
while(!isroot(x))//当前点不是根
{
if(!isroot(f[x]))//父亲也不是根
{
if((rson(f[x])==x)^(rson(f[f[x]])==f[x]))//不在一边
rotate(x,lson(f[x])==x);//旋转当前节点
else
rotate(f[x],lson(f[f[x]])==f[x]);//链的情况,旋转父亲节点才能改变形态,旋转父亲节点
}
rotate(x,lson(f[x])==x);
}
push_up(x);
}
void access(int p)//将当前点通到根节点
{//断开当前点连的实链,到根节点连一条实链
int t=0;//因为当前点是这条链的最后一个点,旋转到根之后右边的点就是当前点之后的点,也就是要断开的店
while(p)
{
splay(p);//把 p 伸展到根节点,
rson(p)=t;//不断让父亲向它连边,也就是连上了实边
t=p;
p=f[p];
push_up(p);
}
}
void makeroot(int p)//是当前点变成原树里的根节点
{
access(p);//到根节点连实链,也就是一颗 splay
splay(p);//将当前点转到根节点
tree[p].laz^=1;//由于 x 点是最后一个,当前为根节点时所有的点都在他的左边,rev一下让所有的点都在他右边,就变成了根了、
}
void link(int x,int y)//连边
{
makeroot(x);//使p变成根节点
f[x]=y;//x变成y的父亲,也就是连了边
}
int find(int x)//找原树的根
{
access(x);//x到根建一颗splay
splay(x);//将 x 伸展到根节点
while(lson(x)) push_down(x),x=lson(x);//因为原树根节点肯定就是中序遍历的第一个点,也就是最顶上的
return x;// splay的最左边的儿子,一直找左儿子就行了
}
void cut(int x,int y)//删边
{
makeroot(x);//x变成根节点
/*access(y);//y通向 x 减了一个实链,也就是一颗 splay,因为 x,y之间有边,所以这颗splay 里面只有两个点
splay(y);//将 y 转到顶部
if(lson(y)!=x ||rson(x)) return;
f[x]=0;//删去原来连边的信息
lson(y)=0;
push_up(x);
push_up(y);*/
if(find(y) == x && f[x]==y && !rson(x))
{
lson(y)=0;
f[x]=0;
push_up(y);
}
}
int query(int x,int y,int opt)
{
makeroot(x);//x成为根
access(y);//生成实链
splay(y);//y伸展到根,也就统计了这条链上的答案
return opt?tree[y].sum:tree[y].Max;
}
void update(int x,int y)//把 x 的值改为 y
{
splay(x);//把 x 转到顶部
tree[x].val=y;
push_up(x);
}
signed main()
{
// freopen("1.in","r",stdin);
// freopen("tree.out","w",stdout);
n=read();
for(int i=1;i<n;i++)
u[i]=read(),v[i]=read();
tree[0].Max=-INF;
for(int i=1;i<n;i++) link(u[i],v[i]);
for(int i=1;i<=n;i++)
{
int x=read();
tree[i].sum=tree[i].Max=tree[i].val=x;
}
m=read();
while(m--)
{
char opt[10];
scanf("%s",opt);
int x=read(),y=read();
if(opt[1]=='M') printf("%lld\n",query(x,y,0));
else if(opt[1]=='S') printf("%lld\n",query(x,y,1));
else if(opt[1]=='H') update(x,y);
}
return 0;
}