holiday/B - 树的统计Count.cpp

197 lines
3.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=3e4+1,N2=N<<1,inf=0x3f3f3f3f;//N2 双向边记得*2
int to[N2],h[N2],ne[N2];
int nid[N],oid[N],top[N],w[N],dep[N],fa[N];
int siz[N],son[N];//子树节点数重边儿子siz最大的儿子
int qs[N<<2],qm[N<<2];
int t,u,v,w1,qu,n,cnt=0,maxson;
char opt[11];
#define ls rt<<1
#define rs rt<<1|1
#define mid ((l+r)>>1) //>>1写成>>2
#define lson ls,l,mid //l写成1
#define rson rs,mid+1,r
#define len (r-l+1)
void add(int u,int v)
{
to[++cnt]=v;
ne[cnt]=h[u];
h[u]=cnt;
}
//以下是线段树
int tot=0;
void build(int rt,int l,int r)
{
if(l==r)
{
qm[rt]=w[oid[l]];
qs[rt]=w[oid[l]];
// printf("l:%d,qm[%d]=w[%d]=%d\n",l,rt,oid[l],qm[rt]);
return;
}
// if(rt<=mid)
build(ls,l,mid);
// else
build(rs,mid+1,r);
qm[rt]=max(qm[ls],qm[rs]);
qs[rt]=qs[ls]+qs[rs];//bug TLE直接等于两个孩子相加
// printf("a[%d]=a[%d]%d/a[%d]%d\n",rt,ls,qm[ls],rs,qm[rs]);
}
inline int qmax(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
// printf("[%d]",rt);
return qm[rt];
}
int res=-inf;
if(L<=mid)res=max(res,qmax(lson,L,R));
if(R>mid)res=max(res,qmax(rson,L,R));
return res;
}
inline int qsum(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
// printf("[%d]",rt);
return qs[rt];
}
int res=0;
if(L<=mid)res+=qsum(lson,L,R);
if(R>mid)res+=qsum(rson,L,R);
return res;
}
//以上是线段树
inline int q(int u,int v,bool tag)
{
int res=0;
if(tag) res=-inf;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
{
swap(u,v);
}
if(tag)res=max(res,qmax(1,1,n,nid[top[u]],nid[u]));
else res+=qsum(1,1,n,nid[top[u]],nid[u]);
// printf("(%d,%d,%d)",u,v,res);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
// printf("(%d,%d,%d)",nid[u],nid[v],res);
if(tag)res=max(res,qmax(1,1,n,nid[u],nid[v]));//son[u]->u边权放在儿子所以连接儿子和爸爸的路要排除爸爸
else res+=qsum(1,1,n,nid[u],nid[v]);//接上,给的是点权就不用
return res;
}
inline void dfs1(int u,int f,int deep)
{
fa[u]=f;
dep[u]=deep;
siz[u]=1;
for(int i=h[u]; i; i=ne[i])
{
int v=to[i];//bug int
if(v==f) continue;//bug 放后了
// printf("(wo[%d]=val[%d]=%d)\n",v,i,val[i]);
dfs1(v,u,deep+1);
siz[u]+=siz[v];
if(son[u]==0||siz[v]>siz[son[u]])
{
son[u]=v;
}
}
// printf("out:%d:fa:%d,dep:%d,siz:%d\n",u,f,deep,siz[u]);
}
inline void dfs2(int u,int tp)
{
nid[u]=++cnt;
oid[cnt]=u;
top[u]=tp;
// printf("%d:nid:%d,nw:%d,top:%d\n",u,cnt,wo[u],topf);
if(!son[u]) return;
dfs2(son[u],tp);
for(int i=h[u]; i; i=ne[i])
{
v=to[i];
if(v!=fa[u]&&v!=son[u])
{
dfs2(v,v);
}
}
}
inline void pushup(int rt)
{
qm[rt]=max(qm[ls],qm[rs]);
qs[rt]=qs[ls]+qs[rs];
}
inline void change(int u,int w1,int rt,int l,int r)
{
if(l==r)
{
qm[rt]=w1;
qs[rt]=w1;
// printf("u:%d,a[%d]=%d(l=r=%d)\n",u,rt,w1,l);
}
else
{
if(u<=mid)
{
change(u,w1,lson);
}
else change(u,w1,rson);
pushup(rt);
// printf("u:%d,a[%d]=a[%d]%d/a[%d]%d\n",u,rt,ls,a[ls],rs,a[rs]);
}
}
int main()
{
//freopen("10.in","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%d",&n);
cnt=0;
// cout<<"\\";
for(int i=1; i<n; i++)
{
scanf("%d%d",&u,&v);// 多打一个%d c0000005 APPCRASH
// printf("(%d)",i);
add(u,v);
add(v,u);
}
for(int i=1; i<=n; i++)
{
scanf("%d",&w[i]);
}
dfs1(1,0,1);
cnt=0;
dfs2(1,1);
build(1,1,cnt);
scanf("%d",&qu);
while(qu--)
{
scanf("%s",opt);
scanf("%d%d",&u,&v);
if(opt[1]=='M')
{
printf("%d\n",q(u,v,1));
}
else if(opt[1]=='S')
{
printf("%d\n",q(u,v,0));
}
else
{
change(nid[u],v,1,1,cnt);
}
}
return 0;
}