黑白树
题目概述
题解
这道题关键是我们的同色连通块该怎么维护。
显然,我们是不大可能将连通块单独出来一个一个维护,因为这样势必就要在我们的
4
,
5
4,5
4,5操作上浪费许多时间。
所以,我们可以考虑在如何在我们本身维护点权的同时能够高效地进行连通块的修改与询问。
显然,由于操作
4
,
5
4,5
4,5,我们应该比较容易想到通过树链剖分来维护。那我们现在需要想的是如何在线段树上维护连通块。
每个树上的连通块,肯定的都一个在树上的子树的根,如果我们在这个根的整个子树上修改的话,也就是把修改放到这个子树的线段树对应的区间上,这样的区间是
O
(
log
n
)
O\left(\log n\right)
O(logn)级别的。
但是,并不是这个区间内的所有点都是跟它一个连通块,我们要将与它不是一个连通块的更改去掉呀。
如果再一个一个区间地暴力去的话显然是不行的,但我们可以尝试在原来懒标记的下传上动点手脚。
这些不行的区间都是原区间对应树或者森林的一些子树,如果我们的原区间行,而子区间不行,必然是原区间中树上的一些异色点覆盖了这个子区间,导致这个子区间中的所有点都不行了。
我们这里就假设看到覆盖这个区间的只有一个点,毕竟如果是多个点一个覆盖一部分的话我们可以尝试让它继续下传后处理。
而这个点肯定是覆盖不了我们的原区间,只能覆盖它的子区间。
于是我们就有个想法,记录下覆盖每个线段树上区间的所有点,如果我们的子区间与的覆盖点多于原区间,那我们的懒标记就不下传。
覆盖一个区间的节点数是
O
(
n
)
O\left(n\right)
O(n)级别的,我们当然不能全部记录,我们只需记录它比它的父亲区间多的部分就行了。
我们上传也是同样的,只要这个区间不比上面的区间覆盖点多,那它肯定就是上一个区间顶端联通块的一部分,可以上传。
我们的修改与查询所分布的
log
n
\log n
logn个区间里,只要到这个区间的路径上不存在阻挡该连通块的覆盖点,那么就可以修改或者查询这个区间。
覆盖点我们可以用
s
e
t
set
set存储它的
d
f
s
dfs
dfs序,这样找一下有没有覆盖点的
d
f
s
dfs
dfs序在我们顶点的子树内即可。
找顶点我们可以跳重链+线段树上二分解决,至于
4
,
5
4,5
4,5操作的修改,我们就直接在线段树上改,只要保证上传的方式还是上面的方式就可以维护连通块。
总时间复杂度 O ( n log 2 n ) O\left(n\log^2n\right) O(nlog2n)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
typedef long double Ld;
typedef pair<LL,LL> pii;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int mod=1e6+7;
const int inv2=499122177;
const int inv3=332748118;
const int jzm=2333;
const int zero=2000;
const int n1=100;
const int lim=100000;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double feps=1e-11;
const double eps=1e-9;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,m,head[MAXN],tot,sz[MAXN],dep[MAXN],wson[MAXN],col[MAXN],val[MAXN];
int dfn[MAXN],rd[MAXN],ltp[MAXN],pre[MAXN],father[MAXN],f[MAXN][20],idx;
struct edge{int to,nxt;}e[MAXN<<1];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
void dosaka1(int u,int fa){
dep[u]=dep[fa]+1;sz[u]=1;father[u]=fa;f[u][0]=fa;
for(int i=1;i<19;i++)f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
dosaka1(v,u);sz[u]+=sz[v];
if(sz[wson[u]]<sz[v])wson[u]=v;
}
}
void dosaka2(int u,int tp){
dfn[u]=++idx;ltp[u]=tp;pre[idx]=u;
if(wson[u])dosaka2(wson[u],tp);
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==wson[u]||v==father[u])continue;
dosaka2(v,v);
}
rd[u]=idx;
}
class SegmentTree{
private:
set<int> bk[MAXN<<2],wt[MAXN<<2];
set<int>::iterator it;
int valw[MAXN<<2],valb[MAXN<<2];
int lzy[MAXN<<2],lzyb[MAXN<<2],lzyw[MAXN<<2];
bool covw[MAXN<<2],covb[MAXN<<2];
void pushdown(int rt){
if(lzy[rt]){
valw[lson]+=lzy[rt];valb[lson]+=lzy[rt];lzy[lson]+=lzy[rt];
valw[rson]+=lzy[rt];valb[rson]+=lzy[rt];lzy[rson]+=lzy[rt];
lzy[rt]=0;
}
if(lzyb[rt]){
if(wt[lson].empty())valb[lson]+=lzyb[rt],lzyb[lson]+=lzyb[rt];
if(wt[rson].empty())valb[rson]+=lzyb[rt],lzyb[rson]+=lzyb[rt];
lzyb[rt]=0;
}
if(lzyw[rt]){
if(bk[lson].empty())valw[lson]+=lzyw[rt],lzyw[lson]+=lzyw[rt];
if(bk[rson].empty())valw[rson]+=lzyw[rt],lzyw[rson]+=lzyw[rt];
lzyw[rt]=0;
}
}
void pushup(int rt){
valw[rt]=valb[rt]=-INF;
if(bk[lson].empty())valw[rt]=max(valw[lson],valw[rt]);
if(bk[rson].empty())valw[rt]=max(valw[rson],valw[rt]);
if(wt[lson].empty())valb[rt]=max(valb[lson],valb[rt]);
if(wt[rson].empty())valb[rt]=max(valb[rson],valb[rt]);
}
void coverup(int rt){
covb[rt]=covb[lson]&covb[rson];
covw[rt]=covw[lson]&covw[rson];
}
bool check(int rt,int l,int r,int c){
it=(c?bk[rt]:wt[rt]).lower_bound(l);
if(it==(c?bk[rt]:wt[rt]).end())return 0;
return (*it)<=r;
}
public:
void build(int rt,int l,int r){
if(l==r){
if(col[pre[l]])valb[rt]=val[pre[l]],covb[rt]=1,valw[rt]=-INF;
else valw[rt]=val[pre[l]],covw[rt]=1,valb[rt]=-INF;
return ;
}
int mid=l+r>>1;build(lson,l,mid);build(rson,mid+1,r);pushup(rt);
}
void update(int rt,int l,int r,int ai){
if(l>r||l>ai||r<ai)return ;
if(l==r){swap(valb[rt],valw[rt]);swap(covb[rt],covw[rt]);return ;}
int mid=l+r>>1;pushdown(rt);
if(ai<=mid)update(lson,l,mid,ai);
if(ai>mid)update(rson,mid+1,r,ai);
coverup(rt);pushup(rt);
}
void insert(int rt,int l,int r,int al,int ar,int ak,int ap){
if(l>r||l>ar||r<al||al>ar)return ;
if(al<=l&&r<=ar){(ap?bk[rt]:wt[rt]).insert(ak);return ;}
int mid=l+r>>1;pushdown(rt);
if(al<=mid)insert(lson,l,mid,al,ar,ak,ap);
if(ar>mid)insert(rson,mid+1,r,al,ar,ak,ap);
pushup(rt);
}
void remove(int rt,int l,int r,int al,int ar,int ak,int ap){
if(l>r||l>ar||r<al||al>ar)return ;
if(al<=l&&r<=ar){(ap?bk[rt]:wt[rt]).erase(ak);return ;}
int mid=l+r>>1;pushdown(rt);
if(al<=mid)remove(lson,l,mid,al,ar,ak,ap);
if(ar>mid)remove(rson,mid+1,r,al,ar,ak,ap);
pushup(rt);
}
void modify(int rt,int l,int r,int al,int ar,int aw){
if(l>r||l>ar||r<al||al>ar)return ;
if(al<=l&&r<=ar){valb[rt]+=aw;valw[rt]+=aw;lzy[rt]+=aw;return ;}
int mid=l+r>>1;pushdown(rt);
if(al<=mid)modify(lson,l,mid,al,ar,aw);
if(ar>mid)modify(rson,mid+1,r,al,ar,aw);
pushup(rt);
}
void Modify(int rt,int l,int r,int al,int ar,int aw,int ap){
if(l>r||l>ar||r<al||al>ar)return ;
if(check(rt,al,ar,ap^1))return ;
if(al<=l&&r<=ar){
if(ap)valb[rt]+=aw,lzyb[rt]+=aw;
else valw[rt]+=aw,lzyw[rt]+=aw;
return ;
}
int mid=l+r>>1;pushdown(rt);
if(al<=mid)Modify(lson,l,mid,al,ar,aw,ap);
if(ar>mid)Modify(rson,mid+1,r,al,ar,aw,ap);
pushup(rt);
}
int query(int rt,int l,int r,int al,int ar,int ap){
if(l>r||l>ar||r<al||al>ar)return 0;
if(check(rt,al,ar,ap^1))return 0;
if(al<=l&&r<=ar)return ap?valb[rt]:valw[rt];
int mid=l+r>>1,res=0;pushdown(rt);
if(al<=mid)res=max(res,query(lson,l,mid,al,ar,ap));
if(ar>mid)res=max(res,query(rson,mid+1,r,al,ar,ap));
return res;
}
int ask(int rt,int l,int r,int al,int ar,int ap){
if(l>r||l>ar||r<al||al>ar)return 0;
if(ap?covb[rt]:covw[rt])return 0;
if(ap?covw[rt]:covb[rt])return min(ar,r);
if(l==r)return l;int mid=l+r>>1;
if(ar>mid){
int tmp=ask(rson,mid+1,r,al,ar,ap);
if(tmp)return tmp;
}
if(al<=mid)return ask(lson,l,mid,al,ar,ap);
return 0;
}
}T;
int FindFa(int x,int dp){for(int i=0;i<19;i++)if((dp>>i)&1)x=f[x][i];return x;}
int ChainFind(int x){
int y=x,ac=col[x];
while(x){
int tmp=T.ask(1,1,n,dfn[ltp[x]],dfn[x],ac);
if(tmp)return FindFa(y,dep[y]-dep[pre[tmp]]-1);
x=father[ltp[x]];
}
return 1;
}
void ChainModify(int u,int v,int w){
for(int fu=ltp[u],fv=ltp[v];fu^fv;u=father[fu],fu=ltp[u]){
if(dep[fu]<dep[fv])swap(fu,fv),swap(u,v);
T.modify(1,1,n,dfn[fu],dfn[u],w);
}
if(dep[u]>dep[v])swap(u,v);
T.modify(1,1,n,dfn[u],dfn[v],w);
}
int main(){
freopen("astill.in","r",stdin);
freopen("astill.out","w",stdout);
read(n);read(m);
for(int i=1;i<n;i++){
int u,v;read(u);read(v);
addEdge(u,v);addEdge(v,u);
}
dosaka1(1,0);dosaka2(1,1);
for(int i=1;i<=n;i++)read(col[i]);
for(int i=1;i<=n;i++)read(val[i]);
for(int i=1;i<=n;i++)T.insert(1,1,n,dfn[i],rd[i],dfn[i],col[i]);
T.build(1,1,n);
for(int i=1;i<=m;i++){
int opt,x,y,w;read(opt);read(x);
if(opt==1)T.remove(1,1,n,dfn[x],rd[x],dfn[x],col[x]),col[x]^=1,
T.insert(1,1,n,dfn[x],rd[x],dfn[x],col[x]),T.update(1,1,n,dfn[x]);
if(opt==2)read(w),x=ChainFind(x),T.Modify(1,1,n,dfn[x],rd[x],w,col[x]);
if(opt==3)x=ChainFind(x),printf("%d\n",T.query(1,1,n,dfn[x],rd[x],col[x]));
if(opt==4)read(y),read(w),ChainModify(x,y,w);
if(opt==5)read(w),T.modify(1,1,n,dfn[x],rd[x],w);
}
return 0;
}