对询问分块,把每
n−−√
n
个询问放在一起处理,并对这些询问涉及到的点建出一棵虚树。
把一个点的反转看成是其到根的路径上的每个点
ti
t
i
的
+1
+
1
或
−1
−
1
,那么虚树上一条边的
ti
t
i
变化都是相同的。我们在处理每一块之前重构所有的
ti
t
i
,然后对于每条边维护所有没有去度假的人的
ti
t
i
,并使之有序且要把
ti
t
i
相等的合并起来,然后只需要再维护一个指针指向正负分界点,对于每个询问就只需要移动
O(n−−√)
O
(
n
)
个指针就能更新答案了。要注意虚树上的关键点需要单独考虑。
使用桶排序就可以做到
O(nn−−√)
O
(
n
n
)
的复杂度了,实测块大小开到
500
500
至
600
600
比较好。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define PB push_back
#define MP make_pair
#define pii pair<int,int>
#define fs first
#define sc second
#define N 100010
#define abs(x) (x<0?-(x):x)
using namespace std;
const int B=600;
int n,m,tote,tim,ans,t[N],r[N],q[N],to[N],nxt[N],con[N],dfn[N],fa[20][N],dep[N],u[N],st[N],id[N],key[N];
vector<int> buc[N<<1];
bool b[N];
int read()
{
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*f;
}
struct node
{
int hd,pnt,sum,dx;
vector<pii> s;
void clr()
{
hd=pnt=sum=dx=0;
s.clear();
}
}g[N];
void ins(int x,int y)
{
to[++tote]=y;nxt[tote]=con[x];con[x]=tote;
}
void dfs(int v,int d)
{
dfn[v]=++tim;dep[v]=d;
for(int p=con[v];p;p=nxt[p])
dfs(to[p],d+1);
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int k=19;k>=0;k--) if(dep[fa[k][x]]>=dep[y]) x=fa[k][x];
if(x==y) return x;
for(int k=19;k>=0;k--) if(fa[k][x]!=fa[k][y]) x=fa[k][x],y=fa[k][y];
return fa[0][x];
}
int rec(int v)
{
int re=b[v];
for(int p=con[v];p;p=nxt[p])
re+=rec(to[p]);
r[v]=t[v]-re;
return re;
}
bool cmp(int x,int y)
{
return dfn[x]<dfn[y];
}
void work(int L,int R)
{
rec(1);
for(int i=L;i<=R;i++)
u[i-L]=q[i];
sort(u,u+R-L+1,cmp);
int top=1,num=1;st[1]=key[1]=1;
for(int i=0;i<=R-L;i++)
{
int LCA=lca(u[i],st[top]);
while(dep[LCA]<dep[st[top]])
{
if(dep[st[top-1]]<=dep[LCA])
{
g[st[top--]].hd=LCA;
if(st[top]!=LCA) st[++top]=LCA,key[++num]=LCA;
break;
}
g[st[top]].hd=st[top-1];
top--;
}
if(st[top]!=u[i]) st[++top]=u[i],key[++num]=u[i];
}
for(;top>1;top--) g[st[top]].hd=st[top-1];
memset(id,0,sizeof(id));
for(int i=1;i<=num;i++)
for(int p=fa[0][key[i]];p!=g[key[i]].hd;p=fa[0][p])
id[p]=key[i];
for(int i=0;i<=(n<<1);i++)
buc[i].clear();
for(int i=1;i<=n;i++)
if(!b[i]) buc[r[i]+n].PB(i);
for(int i=0;i<=(n<<1);i++)
for(int j=0;j<buc[i].size();j++)
if(id[buc[i][j]])
{
int o=id[buc[i][j]],sz=g[o].s.size();
if(sz&&g[o].s[sz-1].fs==i-n) g[o].s[sz-1].sc++;
else g[o].s.PB(MP(i-n,1));
}
for(int i=1;i<=num;i++)
for(int k=key[i];g[k].pnt<g[k].s.size()&&g[k].s[g[k].pnt].fs<0;g[k].pnt++) ;
for(int i=L;i<=R;i++)
{
b[q[i]]^=1;
if(!b[q[i]])
{
r[q[i]]++;
if(r[q[i]]<0) ans++;
for(int p=q[i];g[p].hd;)
{
g[p].dx++;
//cout<<g[p].dx<<' '<<g[p].pnt<<endl;
if(g[p].pnt&&g[p].s[g[p].pnt-1].fs+g[p].dx>=0) g[p].pnt--,ans-=g[p].s[g[p].pnt].sc;
p=g[p].hd;
r[p]++;
if(b[p]==0&&r[p]==0) ans--;
}
}
else
{
if(r[q[i]]<0) ans--;
r[q[i]]--;
for(int p=q[i];g[p].hd;)
{
g[p].dx--;
if(g[p].pnt<g[p].s.size()&&g[p].s[g[p].pnt].fs+g[p].dx<0) ans+=g[p].s[g[p].pnt].sc,g[p].pnt++;
p=g[p].hd;
r[p]--;
if(b[p]==0&&r[p]==-1) ans++;
}
}
printf("%d ",ans);
}
for(int i=1;i<=num;i++)
g[key[i]].clr();
}
int main()
{
n=read();m=read();
for(int i=2;i<=n;i++)
ins(fa[0][i]=read(),i);
for(int k=1;(1<<k)<n;k++)
for(int i=1;i<=n;i++)
fa[k][i]=fa[k-1][fa[k-1][i]];
for(int i=1;i<=n;i++)
t[i]=read();
for(int i=1;i<=m;i++)
q[i]=read(),q[i]=abs(q[i]);
dfs(1,1);
for(int i=1;i<=m;i+=B)
work(i,min(i+B-1,m));
return 0;
}