暴力竟然跑得极快极快,理论 O(n2) 的比 O(nlog2n) 的快得多得多。。。
其实因为这里的 N 只有 105 ,而我的暴力又是找过重心以后的,所以实际情况比 O(n2) 要小得多。
GDOI2015有一道题,也是 N≤105 ,可是标程是 O(n2) 的,而且是后缀数组,常数较大,竟然可以过。。。
有一题, N≤500 ,要跑floyd,但是 O(5003) 比较玄学,依然能过。
回到正题,此题可以用动态点分治做,当然,也可以用一种神奇的算法链剖维护。
我打了后者。
首先 Ans=num∗dis[v]+sum−2∑u∈blackdis[lca(u,v)]
前面不带 ∑ 的部分直接乱搞,后面的具体是每次染黑一个点就把该点到根的所有点的标记全部+1,查询就是该点到根的所有点到起父亲的边的边权乘标记个数。
其实是一种线段覆盖的思想。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,v) for(int i=last[v];i;i=next[i])
using namespace std;
typedef long long ll;
const int N=100010,M=N*2;
int n,m,tot,to[M],wei[M],next[M],last[N];
int fa[N],w[N],re[N],son[N],size[N],top[N];
ll c[N],dis[N];
struct segment
{
ll x,y,lz;
}a[N*4];
bool black[N];
void link(int u,int v,int w)
{
to[++tot]=v,wei[tot]=w,next[tot]=last[u],last[u]=tot;
}
void dfs1(int v,int from,int x)
{
int k=0;
size[v]=1,dis[v]=x;
efo(i,v)
{
int u=to[i];
if(u==from) continue;
dfs1(u,v,x+wei[i]);
size[v]+=size[u];
if(size[u]>size[k]) k=u;
}
son[v]=k;
}
void dfs2(int v,int from,int p)
{
top[v]=p,w[v]=++m,re[m]=v;
if(!son[v]) return;
dfs2(son[v],v,p);
efo(i,v)
{
int u=to[i];
if(u==from || u==son[v]) continue;
dfs2(u,v,u);
}
}
void build(int v,int l,int r)
{
if(l==r)
{
a[v].y=c[re[l]];
return;
}
int mid=(l+r)>>1;
build(v+v,l,mid),build(v+v+1,mid+1,r);
a[v].y=a[v+v].y+a[v+v+1].y;
}
void down(int v,int l,int r)
{
if(a[v].lz==0) return;
int mid=(l+r)>>1;
a[v+v].x+=a[v+v].y*a[v].lz,a[v+v].lz+=a[v].lz;
a[v+v+1].x+=a[v+v+1].y*a[v].lz,a[v+v+1].lz+=a[v].lz;
a[v].lz=0;
}
void modify(int v,int l,int r,int x,int y)
{
if(l==x && r==y)
{
a[v].x+=a[v].y,a[v].lz++;
return;
}
down(v,l,r);
int mid=(l+r)>>1;
if(y<=mid) modify(v+v,l,mid,x,y);
else
if(x>mid) modify(v+v+1,mid+1,r,x,y);
else
modify(v+v,l,mid,x,mid),modify(v+v+1,mid+1,r,mid+1,y);
a[v].x=a[v+v].x+a[v+v+1].x;
}
void change(int v)
{
for(;top[v]>=1;v=fa[top[v]])
{
modify(1,1,n,w[top[v]],w[v]);
if(fa[top[v]]<1) break;
}
}
ll find(int v,int l,int r,int x,int y)
{
if(l==x && r==y) return a[v].x;
down(v,l,r);
int mid=(l+r)>>1;
if(y<=mid) return find(v+v,l,mid,x,y);
else
if(x>mid) return find(v+v+1,mid+1,r,x,y);
else
return find(v+v,l,mid,x,mid)+find(v+v+1,mid+1,r,mid+1,y);
}
ll query(int v)
{
ll t=0;
for(;top[v]>=1;v=fa[top[v]])
{
t+=find(1,1,n,w[top[v]],w[v]);
if(fa[top[v]]<1) break;
}
return t;
}
int main()
{
int _,t,x;
ll num=0,sum=0;
scanf("%d %d",&n,&_);
fo(i,2,n) scanf("%d",&fa[i]),fa[i]++;
fo(i,2,n)
{
scanf("%lld",&c[i]);
link(i,fa[i],c[i]),link(fa[i],i,c[i]);
}
dfs1(1,0,0);
dfs2(1,0,1);
build(1,1,n);
while(_--)
{
scanf("%d %d",&t,&x);x++;
if(t==1)
{
if(black[x]) continue;
black[x]=1,num++,sum+=dis[x];
change(x);
}
else
printf("%lld\n",num*dis[x]+sum-2*query(x));
}
return 0;
}