【BZOJ-3681】Arietta 網絡流 + 線段樹合併

3681: Arietta

Time Limit: 20 Sec  Memory Limit: 64 MB
Submit: 182  Solved: 70
[Submit][Status][Discuss]

Description

Arietta 的命運與她的妹妹不一樣,在她的妹妹已經走進學院的時候,她仍然留在山村中。
可是她從未中止過和戀人 Velding 的書信往來。一天,她準備去探訪他。
對着窗外的陽光,臨行前她再次彈起了琴。
她的琴的發聲十分特殊。
讓咱們給一個形式化的定義吧。
全部的 n 個音符造成一棵由音符 C ( 1 號節點) 構成的有根樹,每個音符有一個音高 Hi 。
Arietta 有 m 個力度,第 i 個力度能彈出 Di 節點的子樹中,音高在 [Li,Ri] 中的任意一個音符。
爲了樂曲的和諧,Arietta 最多會彈奏第 i 個力度 Ti 次。
Arietta 想知道她最多能彈出多少個音符。php

Input

輸入共 m + 3 行。
第一行兩個整數 n, m ,意義如題目所述。
第二行 n - 1 個整數 Pi ,表示節點 i ( i = 2 . . . n ) 的父親節點的編號。
第三行 n 個整數 Hi 。
接下來的 m 行,每行四個整數 Li,Ri,D,Ti
ios

Output

輸出一個整數表示 Arietta 最多能彈奏多少音符。
數據範圍與約定
對於 100% 的數據,1 ≤ n, m ≤ 10000 。
對於全部數據,1 ≤ Hi , Ti , Pi ≤ n, 1 ≤ Li ≤ Ri ≤ n 。
數組

Sample Input

5 2
1 1 2 2
5 3 2 4 1
1 3 2 1
3 5 1 4

Sample Output

4

HINT

第一個力度彈奏音符5,第二個力度彈奏音符1,2,4。網絡

數據範圍與約定

對於 100% 的數據,1 ≤ n, m ≤ 10000 。

對於全部數據1<=Hi,Ti,Pi<=N,1<=Li<=Ri<=N優化

Source

Shinrein祭 #1spa

Solution

怎麼看都和A+B problem很相似,因此確定是 主席樹優化構圖 + 網絡流blog

這樣的樹形態主席樹,用線段樹合併會很方便獲得每一個子樹對應的主席樹形態,注意一下細節就行了,數組大小得斟酌着開!!!..ip

這樣的話,點數大概是$O(2NlogN+M)$級,邊數大概在$O(2NlogN+MlogL)$級。內存

可是這題內存64M仍是有點小卡的..一開始沒有判斷lson和rson是否存在就直接連邊了,形成連了大量無用的邊,MLE了一次,在連邊的時候注意一下是否有意義便可。get

不知道程序裏好像有什麼奇怪的地方..本機拍一組大樣例RE..由於連邊時有某個點編號連完後變大了10倍..其他的應該是沒什麼問題..誰知道這沙茶程序出了啥毛病(捂臉

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
	while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
	return x*f;
}

#define MAXN 400010
#define INF 0x7fffffff

int N,M,sz=1;

struct EdgeNode{
	int next,to,cap;
}edge[1000010];
int head[MAXN],cnt=1;
inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;}
inline void InsertEdge(int u,int v,int w) {/*printf("<%d,%d>%d\n",u,v,w);*/ AddEdge(u,v,w); AddEdge(v,u,0);}

int h[MAXN],cur[MAXN],S,T;
queue<int>q;
inline bool Bfs()
{
    for (int i=0; i<=sz; i++) h[i]=-1;
    q.push(S); h[S]=0;
    while (!q.empty()) {
        int now=q.front(); q.pop();
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].cap && h[edge[i].to]==-1)
                h[edge[i].to]=h[now]+1,q.push(edge[i].to);
    }
    return h[T]!=-1;
}
 
inline int Dfs(int now,int low)
{
    if (now==T) return low;
    int w,used=0;
    for (int i=cur[now]; i; i=edge[i].next)
        if (edge[i].cap && h[edge[i].to]==h[now]+1) {
            int w=Dfs(edge[i].to,min(low-used,edge[i].cap));
            edge[i].cap-=w; edge[i^1].cap+=w; used+=w;
            if (used==low) return used;
            if (edge[i].cap) cur[now]=i;
        }
    if (!used) h[now]=-1;
    return used;
}
 
inline int Dinic()
{
    int re=0;
    while (Bfs()) {
        for (int i=0; i<=sz; i++) cur[i]=head[i];
        re+=Dfs(S,INF);
    }
    return re;
}

struct SgtNode{
	int lson,rson;
}tree[10010*80];

int root[MAXN];
inline void Insert(int &x,int l,int r,int pos)
{
	x=++sz;
	if (l==r) {
		InsertEdge(x,T,1);
		return;
	}
	int mid=(l+r)>>1;
	if (pos<=mid) Insert(tree[x].lson,l,mid,pos),InsertEdge(x,tree[x].lson,INF);
		else Insert(tree[x].rson,mid+1,r,pos),InsertEdge(x,tree[x].rson,INF);
}

inline int Merge(int x,int y,int l,int r)
{
	if (!x || !y) return x|y;
	int z=++sz;
	if (l==r) {
		InsertEdge(z,x,INF),InsertEdge(z,y,INF);
		return z;
	}
	int mid=(l+r)>>1;
	tree[z].lson=Merge(tree[x].lson,tree[y].lson,l,mid);
	if (tree[z].lson) InsertEdge(z,tree[z].lson,INF);
	tree[z].rson=Merge(tree[x].rson,tree[y].rson,mid+1,r);
	if (tree[z].rson) InsertEdge(z,tree[z].rson,INF);
	return z;
}

inline void Query(int x,int l,int r,int L,int R,int id)
{
	if (!x) return;
	if (L<=l && R>=r) {
		InsertEdge(id,x,INF);
		return;
	}
	int mid=(l+r)>>1;
	if (L<=mid) Query(tree[x].lson,l,mid,L,R,id);
	if (R>mid) Query(tree[x].rson,mid+1,r,L,R,id);
}

vector<int>son[MAXN];
inline void DFS(int now)
{
	for (int i=0; i<son[now].size(); i++) {
		DFS(son[now][i]);
		root[now]=Merge(root[now],root[son[now][i]],1,N);
	}
}

int main()
{
	
	N=read(),M=read();
	
	for (int i=2,x; i<=N; i++) x=read(),son[x].push_back(i);
	
	S=0,T=1;
	
	for (int i=1,x; i<=N; i++) x=read(),Insert(root[i],1,N,x);
	
	DFS(1);
	
	for (int i=1; i<=M; i++) {
		int L=read(),R=read(),D=read(),Ti=read();
		InsertEdge(S,++sz,Ti); Query(root[D],1,N,L,R,sz);
	}
	
	printf("%d\n",Dinic());
	
	return 0;
}
相關文章
相關標籤/搜索