/* 一颗树,有n个点,每个点有一个权值。 每次查询 u->v 的路径上(u,v,w) 先取一个点权,在取一个点权,使后者减去前者的值最大(如果为负数,输出0),并且走过这条路 径之后,路径上每个点的点权都加上w。 */ //下面的代码是修改模板之后的,里面有好多函数是没有用到的,与模板有很好的继承性 #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 50010; struct Node *null; struct Node{ Node *fa,*ch[2]; int val,size; //val是该点的权重,size是以它为根的子树的大小。 int add; int mm; int Max,Min; int rmm; int rev; inline void clear(int _val){ //初始化该点的点权。 fa = ch[0] = ch[1] = null; val = Max = Min = _val; mm = 0; rmm = 0; rev = 0; add = 0; } inline void push_up(){ // if(this == null)return; mm = 0; mm = max(mm,ch[0]->mm); mm = max(mm,ch[1]->mm); mm = max(mm,max(val,ch[1]->Max)-ch[0]->Min); mm = max(mm,ch[1]->Max-min(ch[0]->Min,val)); rmm = 0; rmm = max(rmm,ch[0]->rmm); rmm = max(rmm,ch[1]->rmm); rmm = max(rmm,max(val,ch[0]->Max)-ch[1]->Min); rmm = max(rmm,ch[0]->Max-min(ch[1]->Min,val)); Max = max(val,max(ch[0]->Max,ch[1]->Max)); Min = min(val,min(ch[0]->Min,ch[1]->Min)); } inline void setc(Node *p,int d){ ch[d] = p; p->fa = this; } inline bool d(){ return fa->ch[1] == this; } inline bool isroot(){ return fa == null || fa->ch[0] != this && fa->ch[1] != this; } inline void flip(){ if(this == null)return; swap(ch[0],ch[1]); swap(mm,rmm); rev ^= 1; } inline void update_add(int w){ if(this == null)return; val += w; Min += w; Max += w; add += w; } inline void push_down(){ if(this == null)return; if(rev){ ch[0]->flip(); ch[1]->flip(); rev = 0; } if(add){ ch[0]->update_add(add);ch[1]->update_add(add); add = 0; } } inline void go(){ if(!isroot())fa->go(); push_down(); } inline void rot(){ Node *f = fa, *ff = fa->fa; int c = d(), cc = fa->d(); f->setc(ch[!c],c); this->setc(f,!c); if(ff->ch[cc] == f)ff->setc(this,cc); else this->fa = ff; f->push_up(); } inline Node* splay(){ go(); while(!isroot()){ if(!fa->isroot()) d()==fa->d() ? fa->rot() : rot(); rot(); } push_up(); return this; } inline Node* access(){ for(Node *p = this,*q = null; p != null; q = p, p = p->fa){ p->splay()->setc(q,1); p->push_up(); } return splay(); } inline Node* find_root(){ Node *x; for(x = access(); x->push_down(), x->ch[0] != null; x = x->ch[0]); return x; } void make_root(){ access()->flip(); } void cut(){ access(); ch[0]->fa = null; ch[0] = null; push_up(); } void cut(Node *x){ //删除该节点和x之间的边。 if(this == x || find_root() != x->find_root())return; else{ x->make_root(); cut(); } } void link(Node *x){ //该节点链接x节点。(即该节点和x节点之间加一条边) if(find_root() == x->find_root())return; else { make_root(); fa = x; } } }; int read() //读入优化 { int ans = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9'){ ans = ans * 10 + ch - '0'; ch = getchar(); } return ans; } Node pool[MAXN],*tail; Node *node[MAXN]; struct Edge{ int to,next; }edge[MAXN*2]; int head[MAXN],tot; void init(){ tot = 0; memset(head,-1,sizeof(head)); } inline void addedge(int u,int v){ edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } int g[MAXN]; int fa[MAXN]; void bfs(int s){ //用来建树 int l,r; g[l=r=1] = s; fa[s] = s; while(l <= r){ int u = g[l++]; for(int i = head[u];i != -1;i = edge[i].next){ int v = edge[i].to; if(v == fa[u])continue; fa[v] = u; node[v]->fa = node[u]; g[++r] = v; } } } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; int n,m; scanf("%d",&T); while(T--){ scanf("%d",&n); tail = pool; null = tail++; null->fa = null->ch[0] = null->ch[1] = null; null->Max = -INF; null->Min = INF; null->mm = 0; null->add = null->rev = 0; for(int i = 1;i <= n;i++){ int v ; //scanf("%d",&v); //初始化点权 v=read(); node[i] = tail++; node[i]->clear(v); } init(); int u,v; for(int i = 1;i < n;i++){ scanf("%d%d",&u,&v); addedge(u,v); //这里本来可以直接用node[u]->link(node[v]);来直接建边的,但是会慢一点,本题会TLE。 addedge(v,u); } bfs(1);//前面一个循环先输入边,dfs用来建树。这样会比每次输一个边就建一条边快好多(本题卡时间就这样做)。 int w; scanf("%d",&m); while(m--){ //scanf("%d%d%d",&u,&v,&w); u=read(); v=read(); w=read(); node[u]->make_root(); node[v]->access(); printf("%d\n",node[v]->mm); node[v]->update_add(w); } } return 0; }