一個LCT,已知每個點的Access次數,每次Access點x時,往上遇到的輕邊數會產生貢獻,求最大貢獻和
先不考慮修改
我們定義輕邊的父親節點爲產生這次貢獻的節點
可以發現每個點產生的貢獻只和其子樹裏相鄰的Access操作是否相同有關,且他們是互相獨立的
於是最大貢獻和=每個點貢獻的最大值的和
考慮一個點貢獻的最大值,設這個子樹裏總Access操作有siz次,幾個孩子的子樹和他自己的Access操作是ai
那麼問題等價於共有siz個球,第i種顏色有ai個球,若擺放的相鄰兩個球顏色不同就會有1的價值,最大化擺放的價值和
設球最多的顏色有k個球,貪心可得最大的價值和就是
於是沒有修改的情況我們可以用一個dfs,O(n)的求出解
對於有修改的情況
我們定義當y是x的兒子且 時y是x的重兒子,否則就是輕兒子
那麼當x有重兒子時x的最大價值是 ,否則是
我們用LCT去維護這個剖分結構
修改一個點,只會影響他的所有祖先的價值,
且因爲當 時,有 ,所以x往上的重邊是不用管的,他們仍然是重邊且價值不變
輕邊只會有log條,對於每條輕邊暴力去重新維護就行了
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void up(ll &a,const ll &b){if(a<b)a=b;}
const int maxn = 510000;
int n,m;
int ai[maxn];
struct edge{int y,nex;}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}
int Fa[maxn];
ll mxs[maxn],siz[maxn],ans;
void dfs(const int x)
{
siz[x]=mxs[x]=ai[x];
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=Fa[x])
{
Fa[y]=x;
dfs(y);
siz[x]+=siz[y];
up(mxs[x],siz[y]);
}
ans+=min(siz[x]-1ll,(siz[x]-mxs[x])*2ll);
}
struct Link_Cut_Tree
{
int son[maxn][2],fa[maxn];
ll fl[maxn],s[maxn],s2[maxn];
bool isrt(int x){ return son[fa[x]][0]!=x&&son[fa[x]][1]!=x; }
void pushdown(int x)
{
if(fl[x])
{
ll fc=fl[x]; fl[x]=0;
int lc=son[x][0],rc=son[x][1];
if(lc) fl[lc]+=fc,s[lc]+=fc;
if(rc) fl[rc]+=fc,s[rc]+=fc;
}
}
int t[maxn],tp;
void Down(int x)
{
while(!isrt(x)) t[++tp]=x,x=fa[x];
t[++tp]=x;
while(tp) pushdown(t[tp--]);
}
void rot(int x)
{
int y=fa[x],z=fa[y];
if(!isrt(y)) son[z][son[z][1]==y]=x;
fa[x]=z;
int l=son[y][1]==x;
fa[son[y][l]=son[x][!l]]=y;
fa[son[x][!l]=y]=x;
}
void splay(int x)
{
for(Down(x);!isrt(x);rot(x))
{
int y=fa[x],z=fa[y];
if(!isrt(y)) rot(((son[y][1]==x)^(son[z][1]==y))?x:y);
}
}
void build()
{
for(int i=1;i<=n;i++) s[i]=siz[i],s2[i]=ai[i];
for(int i=2;i<=n;i++)
{
int x=Fa[i],y=i;
fa[y]=x;
if(s[y]*2ll>s[x]) son[x][1]=y;
}
}
int go(int x,int dir)
{
while(son[x][dir]) x=son[x][dir];
return x;
}
void Access(int x,int c)
{
int tx=0;
splay(x); if(son[x][1]) splay(tx=go(son[x][1],0));
splay(x); if(son[x][1]) rot(son[x][1]);
if(tx) up(mxs[x],s[tx]);
ans-=min(s[x]-1,(s[x]-mxs[x])*2ll);
s[x]+=c; s2[x]+=c; fl[x]+=c; up(mxs[x],s2[x]);
splay(x);
if(s[tx]*2ll<=s[x]) son[x][1]=0,up(mxs[x],s[tx]);
ans+=min(s[x]-1,(s[x]-mxs[x])*2ll);
while(x)
{
splay(x); splay(x=go(x,0));
int y=fa[x],ty=0;
if(!y) break;
splay(y); if(son[y][1]) splay(ty=go(son[y][1],0));
splay(y); if(son[y][1]) rot(son[y][1]);
if(ty) up(mxs[y],s[ty]);
ans-=min(s[y]-1,(s[y]-mxs[y])*2ll);
s[y]+=c; fl[y]+=c; up(mxs[y],s[x]);
splay(y);
if(s[x]*2ll>s[y]) son[y][1]=x;
else if(ty&&2*s[ty]<=s[y]) son[y][1]=0;
ans+=min(s[y]-1,(s[y]-mxs[y])*2ll);
x=y;
}
}
}LCT;
int main()
{
read(n); read(m);
for(int i=1;i<=n;i++) read(ai[i]);
for(int i=1;i<n;i++)
{
int x,y; read(x); read(y);
ins(x,y); ins(y,x);
}
dfs(1); printf("%lld\n",ans);
LCT.build();
while(m--)
{
int x,w; read(x); read(w);
LCT.Access(x,w);
printf("%lld\n",ans);
}
return 0;
}