# bzoj5210最大连通子块和 （动态dp+卡常好题）

（全网都没有用矩阵转移的动态dp，让我很慌张）

$ans1[i]=max(ans1[i],ans1[p]),ans1[i]=max(ans1[i],dp1[i])$

$$p$$$$x$$的重儿子的话

f[x] f[x] -inf
-inf 0 -inf
f[x] ans1[x] 0


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
#define rint register int
using namespace std;
//char buf[100010],*buff = buf + 100000;

//#define getchar() (buff == buf + 100000 ? (fread(buf,1,100000,stdin),buff = buf) : 0,*buff++)

{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}

const int maxn = 2e5+1e2;
const int maxm = 2*maxn;
const ll inf = -1e15;

struct Node{
priority_queue<ll> q1,q2;
inline void push(ll x) {q1.push(x);}
inline void erase(ll x) {q2.push(x);}
inline ll top(){while ((!q2.empty()) && (q1.top()==q2.top())) q1.pop(),q2.pop(); return q1.top();}
};

Node ans[maxn];

struct Ju{
int x,y;
ll a[3][3];
Ju operator * (Ju b)
{
Ju ans;
ans.x=x;
ans.y=b.y;
for (rint i=0;i<=ans.x;++i)
{
for (rint j=0;j<=ans.y;++j)
{
ll uu = inf;
for (rint k=0;k<=y;++k)
uu=max(uu,a[i][k]+b.a[k][j]);
ans.a[i][j]=uu;
}
}
return ans;
}
};

int point[maxn],nxt[maxm],to[maxm];
int cnt,n,m;
int top[maxn],newnum[maxn],fa[maxn],son[maxn],size[maxn];
Ju f[4*maxn];
//Ju pre[maxn];
ll dp1[maxn],dp[maxn];
ll ans1[maxn];
int back[maxn];
int tot;
int tail[maxn];
ll val[maxn];
int leaf[maxn];
Ju caonima;

struct pp{
ll cao,kao;
};

pp cnm[maxn];

{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}

inline void up(int root)
{
f[root]=f[2*root+1]*f[2*root];
}

void build(int root,int l,int r)
{
if (l==r)
{
int ymh = back[l];

if (tail[top[ymh]]==ymh)
{
f[root].x=0;
f[root].y=2;
f[root].a[0][0]=dp[ymh];
f[root].a[0][1]=max(dp[ymh],0ll);
}
else
{   f[root].x=f[root].y=2;
f[root].a[0][0]=dp[ymh];
f[root].a[0][1]=dp[ymh];
f[root].a[0][2]=inf;
f[root].a[1][0]=inf;
f[root].a[1][2]=inf;
f[root].a[2][0]=dp[ymh];
f[root].a[2][1]=ans[ymh].top();
}
leaf[ymh]=root;
return;
}
int mid = l+r >> 1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
up(root);
}

void update(int root,int l,int r,int x)
{
if (l==r)
{
f[root]=caonima;
return;
}
int mid = l+r >> 1;
if (x<=mid) update(root<<1,l,mid,x);
else update(root<<1|1,mid+1,r,x);
up(root);
}

Ju query(int root,int l,int r,int x,int y)
{
if(x<=l && r<=y)
{
return f[root];
}
int mid = l+r >> 1;
if (y<=mid) return query(root<<1,l,mid,x,y);
if (x>mid) return query(root<<1|1,mid+1,r,x,y);
return query(root<<1|1,mid+1,r,x,y)*query(root<<1,l,mid,x,y);
}

void dfs1(int x,int faa)
{
size[x]=1;
int maxson=-1;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==faa) continue;
fa[p]=x;
dfs1(p,x);
size[x]+=size[p];
if (size[p]>maxson)
{
maxson=size[p];
son[x]=p;
}
}
}

void dfs2(int x,int chain)
{
top[x]=chain;
tail[chain]=x;
newnum[x]=++tot;
back[tot]=x;
if (!son[x]) return;
dfs2(son[x],chain);
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (!newnum[p]) dfs2(p,p);
}
}

void solve(int x,int fa)
{
dp[x]=dp1[x]=val[x];
ans1[x]=val[x];
for (rint i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==fa) continue;
solve(p,x);
dp1[x]=max(dp1[x],dp1[x]+dp1[p]);
ans1[x]=max(ans1[x],ans1[p]);
if (p!=son[x]) dp[x]=max(dp[x],dp[x]+dp1[p]),ans[x].push(ans1[p]);
}
ans[x].push(dp[x]);
ans[x].push(0);
//cout<<x<<endl;
ans1[x]=max(ans1[x],dp1[x]);
ans1[x]=max(ans1[x],0ll);
//cout<<x<<endl;
}

void modify(int x,ll y)
{
Ju tmp = f[leaf[x]];
if (tail[top[x]]==x)
{
tmp.a[0][0]+=y-val[x];
tmp.a[0][1]=max(0ll,tmp.a[0][0]);
}
else
{
ans[x].erase(tmp.a[0][0]);
tmp.a[0][0]+=y-val[x];
tmp.a[0][1]=tmp.a[0][0];
ans[x].push(tmp.a[0][0]);
tmp.a[2][0]=tmp.a[0][0];
tmp.a[2][1]=ans[x].top();
}
val[x]=y;
caonima=tmp;
update(1,1,n,newnum[x]);
//cout<<x<<" "<<top[x]<<endl;
for (rint now = top[x];now!=1;now=top[now])
{
//cout<<now<<endl;
int faa = fa[now];
//Ju ymh = query(1,1,n,newnum[faa],newnum[faa]);
Ju ymh = f[leaf[faa]];
Ju lyf;
if (newnum[now]!=newnum[tail[top[now]]])
lyf= query(1,1,n,newnum[now],newnum[tail[top[now]]]);
else
lyf = f[leaf[now]];
ans[faa].erase(cnm[now].kao);
ans[faa].erase(ymh.a[0][0]);
ymh.a[0][0]+=max(lyf.a[0][0],0ll)-max(cnm[now].cao,0ll);
ymh.a[0][1]=ymh.a[0][0];
ymh.a[2][0]=ymh.a[0][0];
ans[faa].push(ymh.a[0][0]);
ans[faa].push(lyf.a[0][1]);
ymh.a[2][1]=ans[faa].top();
caonima=ymh;
update(1,1,n,newnum[faa]);
cnm[now].kao=lyf.a[0][1];
cnm[now].cao=lyf.a[0][0];
now=fa[now];
}
}

int q;
char c;

signed main()
{
//freopen("5210.in","r",stdin);
//freopen("ymh.out","w",stdout);
//cout<<n<<" "<<q<<endl;
for (rint i=1;i<n;i++)
{
}
dfs1(1,0);
dfs2(1,1);
solve(1,0);
//cout<<1<<endl;
build(1,1,n);
//cout<<ans1[2]<<" "<<dp[2]<<" "<<dp1[2]<<endl;
for (rint i=1;i<=n;++i)
{
Ju ymh = query(1,1,n,newnum[i],newnum[tail[top[i]]]);
cnm[i].cao=ymh.a[0][0];
cnm[i].kao=ymh.a[0][1];
}
for (rint i=1;i<=q;++i)
{
c=getchar();
while (c<'A' || c>'Z') c=getchar();
if (c=='M')
{