Obviously it's the largest flow of mapping. However, the number of edges exploded.
We consider that each node maintains a line segment tree representing sub-tree information to optimize the mapping, and then the number of edges or explosion.
Let's consider building a chairman tree on the tree to optimize the mapping. Yes, it seems possible. However, the sub-tree information can't be reduced (maintaining the label of the point whose weight is x)
At this point we need to use a black technology: dsu on tree!
That's heuristic tree merging. More references: portal
Maybe it's about dividing the chain between the light and the heavy, and then the light and the violence, so the complexity is scientific! _________
Specifically, the line segment tree at each point is persistent from its heavy son, and then violently inserts into all the light son's subtrees. Because each point jumps up the most logn heavy chains, so a point is inserted into the logn at most times by violence, so the space complexity and time complexity are O(nlog2n).
Then we succeeded in optimizing the mapping! Points O(nlog2n+m+n) and edges O(2nlog2n+mlogn).
Note that there may be multiple labels for the same weight in a line segment tree of a point, so special treatment of leaves should be taken when persistence is possible.
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 10010
#define M 1300010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,a[N],rt[N],owo=0,sz[N],son[N],h[M],num=1,lev[M],cur[M],T,ans=0;
vector<int>Son[N];
struct node{
int lc,rc;
}tr[M];
struct edge{
int to,next,val;
}data[M<<1];
inline void add(int x,int y,int val){
data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=0;
}
inline void ins(int &p,int l,int r,int x,int id){
if(l==r){++owo;add(owo+n,id,inf);if(p) add(owo+n,p+n,inf);p=owo;return;}
tr[++owo]=tr[p];p=owo;int mid=l+r>>1;
if(x<=mid) ins(tr[p].lc,l,mid,x,id);
else ins(tr[p].rc,mid+1,r,x,id);
}
void dfs1(int x,int id){
ins(rt[id],1,n,a[x],x);
for(int i=0;i<Son[x].size();++i) dfs1(Son[x][i],id);
}
void dfs(int x){
sz[x]=1;son[x]=0;
for(int i=0;i<Son[x].size();++i){
int y=Son[x][i];dfs(y);if(sz[y]>sz[son[x]]) son[x]=y;sz[x]+=sz[y];
}rt[x]=rt[son[x]];ins(rt[x],1,n,a[x],x);
for(int i=0;i<Son[x].size();++i){
int y=Son[x][i];if(y!=son[x]) dfs1(y,x);
}
}
inline void cover(int p,int l,int r,int x,int y){
if(!p) return;
if(x<=l&&r<=y){add(owo,p+n,inf);return;}
int mid=l+r>>1;
if(x<=mid) cover(tr[p].lc,l,mid,x,y);
if(y>mid) cover(tr[p].rc,mid+1,r,x,y);
}
inline bool bfs(){
queue<int>q;for(int i=0;i<=T;++i) lev[i]=0;
q.push(0);lev[0]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(lev[y]||!data[i].val) continue;
lev[y]=lev[x]+1;if(y==T) return 1;q.push(y);
}
}return 0;
}
inline int dinic(int x,int low){
if(x==T) return low;int tmp=low;
for(int &i=cur[x];i;i=data[i].next){
int y=data[i].to;if(lev[y]!=lev[x]+1||!data[i].val) continue;
int res=dinic(y,min(tmp,data[i].val));
if(!res) lev[y]=0;else tmp-=res,data[i].val-=res,data[i^1].val+=res;
if(!tmp) return low;
}return low-tmp;
}
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();
for(int i=2;i<=n;++i) Son[read()].push_back(i);
for(int i=1;i<=n;++i) a[i]=read();dfs(1);
for(int i=1;i<=owo;++i){
if(tr[i].lc) add(i+n,tr[i].lc+n,inf);
if(tr[i].rc) add(i+n,tr[i].rc+n,inf);
}owo+=n;
while(m--){
int l=read(),r=read(),x=read(),val=read();
add(0,++owo,val);cover(rt[x],1,n,l,r);
}T=++owo;for(int i=1;i<=n;++i) add(i,T,1);
while(bfs()){memcpy(cur,h,sizeof(h));ans+=dinic(0,inf);}
printf("%d\n",ans);
return 0;
}