感觉是树剖和lct的一种结合,把树剖的log^2变成log,把lct的常数变小,但是能维护的东西也有局限性...
实际上就是有时候维护的东西不需要lct的link-cut操作,所以可以将树建成一棵棵二叉平衡树连在一起而不需要splay。具体建法就是先轻重链剖分,对每条重链建一棵bst,然后这棵bst的根通过虚边连向这棵bst内深度最浅的点在原树中的父亲。而对于每条重链建bst时,注意为了保证平衡,不是直接取中间的那个点,而是对重链上每个点赋一个轻儿子子树siz和的权值,找到带权中心(使左右权值和尽可能相等的点),然后递归建树。考虑一下复杂度:首先因为轻重链剖分,所以从一棵bst的根往上走一步树的大小一定*2,在考虑我们对重链建的bst按轻儿子子树大小建,这样又可以保证在bst上往上走一步树的大小也一定*2,所以这样就保证这样建的全局平衡二叉树树高是log的。
信息的维护基本就和lct维护区间信息一样,可以做一些动态dp之类的题目。
模板题:https://www.luogu.org/problemnew/show/P4751
这题很卡,交了10发1发过其它全90,看评测机温度...
代码:(其实不长都是卡常痕迹...)
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
const int inf=1e9;
const int BF=1e7;
char gc()
{
static char buf[BF];
static int len=0,ps=0;
if(ps==len)ps=0,len=fread(buf,1,BF,stdin);
if(ps==len)exit(0);
return buf[ps++];
}
template<class T>
void rd(T &x)
{
char c=gc();x=0;bool f=0;
while(!isdigit(c))f|=(c=='-'),c=gc();
while(isdigit(c))x=x*10+c-48,c=gc();
if(f)x=-x;
}
template<class T>
void print(T x)
{
static int ppp[30],pnum;
pnum=0;
if(x<0)putchar('-'),x=-x;
if(x==0)putchar('0');
while(x)ppp[++pnum]=x%10,x/=10;
for(int i=pnum;i>=1;i--)putchar('0'+ppp[i]);
putchar('\n');
}
void Mx(int &x,int y)
{x=max(x,y);}
int n,m,a[N];
int son[N],siz[N];
int f[N],g[N];
vector<int>mp[N];
struct Mat{
int a[2][2];
Mat(){memset(a,-63,sizeof a);}
int ask(){return max(a[0][0],a[1][0]);}
void in(int x,int y)
{a[0][0]=a[0][1]=x,a[1][0]=y,a[1][1]=-inf;}
};
Mat operator *(const Mat &x,const Mat &y)
{
Mat res;
res.a[0][0]=max(x.a[0][0]+y.a[0][0],x.a[0][1]+y.a[1][0]);
res.a[0][1]=max(x.a[0][0]+y.a[0][1],x.a[0][1]+y.a[1][1]);
res.a[1][0]=max(x.a[1][0]+y.a[0][0],x.a[1][1]+y.a[1][0]);
res.a[1][1]=max(x.a[1][0]+y.a[0][1],x.a[1][1]+y.a[1][1]);
return res;
}
void dfs0(int x,int fa)
{
siz[x]=1,f[x]=a[x],g[x]=0;
for(int v,i=0;i<mp[x].size();i++)
{
v=mp[x][i];
if(v==fa)continue;
dfs0(v,x),siz[x]+=siz[v];
if(siz[v]>siz[son[x]])son[x]=v;
f[x]+=g[v],g[x]+=max(f[v],g[v]);
}
}
void dfs1(int x,int fa)
{
if(son[x])
{
f[x]-=g[son[x]],g[x]-=max(f[son[x]],g[son[x]]);
for(int v,i=0;i<mp[x].size();i++)
{
v=mp[x][i];
if(v==fa)continue;
dfs1(v,x);
}
}
}
namespace gbt{
Mat dp[N],seg[N];
int rt,tax[N],tnum,ch[N][2],fa[N],las_ans=0;
bool isr(int x)
{return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x);}
void push_up(int x)
{
seg[x]=dp[x];
if(ch[x][0])seg[x]=seg[ch[x][0]]*seg[x];
if(ch[x][1])seg[x]=seg[x]*seg[ch[x][1]];
}
int bd_chain(int l,int r)
{
if(l>r)return 0;
int sum=0,nw=0;
for(int i=l;i<=r;i++)
sum+=siz[tax[i]]-siz[son[tax[i]]];
for(int i=l;i<=r;i++)
{
nw+=siz[tax[i]]-siz[son[tax[i]]];
if(nw*2>=sum)
{
int x=tax[i];
ch[x][0]=bd_chain(l,i-1);
ch[x][1]=bd_chain(i+1,r);
fa[ch[x][0]]=fa[ch[x][1]]=x;
push_up(x);
return x;
}
}
}
int bd(int top,int f)
{
for(int x=top;x;f=x,x=son[x])
{
for(int v,i=0;i<mp[x].size();i++)
{
v=mp[x][i];
if(v==son[x]||v==f)continue;
fa[bd(v,x)]=x;
}
}
tnum=0;
for(int x=top;x;x=son[x])tax[++tnum]=x;
return bd_chain(1,tnum);
}
void init()
{
for(int i=1;i<=n;i++)
dp[i].in(g[i],f[i]);
rt=bd(1,0);
}
void qry(int x,int y)
{
int bf_g,bf_f,nx_g,nx_f;
bool flg;
f[x]+=y-a[x],a[x]=y;
while(x)
{
flg=isr(x);
if(flg)bf_g=seg[x].a[0][0],bf_f=seg[x].a[1][0];
dp[x].in(g[x],f[x]),push_up(x);
if(flg)nx_g=seg[x].a[0][0],nx_f=seg[x].a[1][0];
if(flg&&fa[x])
{
g[fa[x]]+=max(nx_f,nx_g)-max(bf_f,bf_g);
f[fa[x]]+=nx_g-bf_g;
}
x=fa[x];
}
print(las_ans=seg[rt].ask());
}
void sol()
{
for(int i=1,x,y;i<=m;i++)
rd(x),x^=las_ans,rd(y),qry(x,y);
}
}
int main()
{
rd(n),rd(m);
for(int i=1;i<=n;i++)
rd(a[i]);
for(int u,v,i=1;i<n;i++)
{
rd(u),rd(v);
mp[u].push_back(v);
mp[v].push_back(u);
}
dfs0(1,0),dfs1(1,0);
gbt::init(),gbt::sol();
}