题解:P11803 【MX-X9-T7】『GROI-R3』此花绽放之时
P11803 【MX-X9-T7】『GROI-R3』此花绽放之时
连通块整体加的操作看上去很不可做,不妨对颜色连通块设置一个代表元,钦定这个连通块中深度最小的点是代表元,那么连通块整体加可以沿用类似线段树懒标记的思想,在代表元处打标记
对于连通块整体加,需要找到
对于
这样就做完了,需要动态开点线段树、
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define fir first
#define sec second
const int N=200010;
int n,Q;
int Col[N];
int fa[N];
int h[N],e[N],ne[N],idx;
void add(int u,int v) { e[idx]=v,ne[idx]=h[u],h[u]=idx++; }
int sz[N],son[N],dep[N];
void dfs1(int u)
{
sz[u]=1; dep[u]=dep[fa[u]]+1;
for (int i=h[u];i!=-1;i=ne[i])
{
int v=e[i]; dfs1(v);
sz[u]+=sz[v];
if (sz[v]>sz[son[u]]) son[u]=v;
}
}
int dfn[N],ti,id[N],top[N];
void dfs2(int u,int tp)
{
id[dfn[u]=++ti]=u; top[u]=tp;
if (!son[u]) return;
dfs2(son[u],tp);
for (int i=h[u];i!=-1;i=ne[i])
{
int v=e[i];
if (v!=son[u]) dfs2(v,v);
}
}
namespace ODT
{
struct Node
{
int l,r;
mutable int v;
Node(int _l,int _r,int _v) { l=_l,r=_r,v=_v; }
bool operator < (const Node &o) const { return l<o.l; }
};
struct odt
{
set<Node> st;
typedef set<Node>::iterator itr;
itr split(int x)
{
if (x>n) return st.end();
itr it=--st.upper_bound({x,0,0});
int l=it->l,r=it->r,v=it->v;
if (l==x) return it;
st.erase(it); st.insert({l,x-1,v});
return st.insert({x,r,v}).first;
}
void assign(int l,int r,int v)
{
itr rit=split(r+1),lit=split(l); st.erase(lit,rit);
itr p=st.insert({l,r,v}).first; lit=rit=p;
while (lit->v==p->v) lit--; lit++;
while (rit->v==p->v) rit++; rit--;
l=lit->l,r=rit->r; st.erase(lit,++rit); st.insert({l,r,v});
}
PII bel(int x)
{
itr it=--st.upper_bound({x,0,0});
return {it->l,it->r};
}
int ask(int x)
{
itr it=--st.upper_bound({x,0,0});
return it->v;
}
} col[N];
} using namespace ODT;
namespace sgt
{
const int T=3e7;
struct Node
{
int lc,rc;
ll dat;
} tr[T];
int rt[N],idx;
void upd(int &u,int lq,int rq,ll v,int l=1,int r=n)
{
if (!u) u=++idx;
if (lq<=l && r<=rq) { tr[u].dat+=v; return; }
int mid=(l+r)>>1;
if (lq<=mid) upd(tr[u].lc,lq,rq,v,l,mid);
if (rq>mid) upd(tr[u].rc,lq,rq,v,mid+1,r);
}
ll ask(int u,int x,int l=1,int r=n)
{
if (!u) return 0;
if (l==r) return tr[u].dat;
int mid=(l+r)>>1;
if (x<=mid) return ask(tr[u].lc,x,l,mid)+tr[u].dat;
else return ask(tr[u].rc,x,mid+1,r)+tr[u].dat;
}
} using namespace sgt;
namespace BIT
{
ll tr[N];
inline int lowbit(int x) { return x & (-x); }
inline void upd(int x,ll v) { for (;x<=n;x+=lowbit(x)) tr[x]+=v; }
inline void modify(int l,int r,ll v) { upd(l,v), upd(r+1,-v); }
inline ll ask(int x) { ll res=0; for (;x;x-=lowbit(x)) res+=tr[x]; return res; }
}
map<int,ll> undo[N];
void psd(int u)
{
int c=col[top[u]].ask(dfn[u]);
auto [l,r]=col[top[u]].bel(dfn[u]);
ll v=ask(rt[c],dfn[fa[u]])-undo[u][c]; undo[u][c]+=v;
upd(rt[c],l,r,v); BIT::modify(l,r,v);
}
int buc[N],len;
void spread(int u)
{
len=0;
while (top[u]) { buc[++len]=top[u]; u=fa[top[u]]; }
for (int i=len;i;i--) if (buc[i]!=1) psd(buc[i]);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> n >> Q;
for (int i=1;i<=n;i++) cin >> Col[i];
memset(h,-1,sizeof(h));
for (int i=2;i<=n;i++)
{
cin >> fa[i];
add(fa[i],i);
}
dfs1(1); dfs2(1,1);
for (int i=1;i<=n;i++) col[i].st.insert({0,n+1,0});
for (int i=1;i<=n;i++) col[top[i]].assign(dfn[i],dfn[i],Col[i]);
while (Q--)
{
int op; cin >> op;
if (op==1)
{
int u,v,c;
cin >> u >> v >> c;
spread(u), spread(v);
while (top[u]!=top[v])
{
if (dep[top[u]]<dep[top[v]]) swap(u,v);
col[top[u]].assign(dfn[top[u]],dfn[u],c);
undo[top[u]][c]=ask(rt[c],dfn[fa[top[u]]]); //清空
u=fa[top[u]];
}
if (dep[u]<dep[v]) swap(u,v);
col[top[u]].assign(dfn[v],dfn[u],c);
if (v==top[u]) undo[v][c]=ask(rt[c],dfn[fa[v]]);
}
else if (op==2)
{
int u,w;
cin >> u >> w;
int tc=col[top[u]].ask(dfn[u]);
int up=u;
while (u)
{
int c=col[top[u]].ask(dfn[u]); if (c!=tc) break;
auto [l,r]=col[top[u]].bel(dfn[u]);
if (l!=dfn[top[u]])
{
up=id[l];
break;
}
else
{
up=top[u];
u=fa[top[u]];
}
}
auto [l,r]=col[top[up]].bel(dfn[up]);
upd(rt[tc],l,r,w), BIT::modify(l,r,w);
}
else
{
int u; cin >> u;
spread(u);
cout << BIT::ask(dfn[u]) << "\n";
}
}
return 0;
}