題目大意
有一棵 個結點的樹,第 個結點有 的收益。
還有 個攝像頭,第 個攝像頭在 這個結點上,能監測它子樹裏所有與 距離不超過 的結點(距離按邊算),黑掉這個攝像頭的代價是 。一個結點被任何攝像頭監測着它就不能獲得收益。
求最大獲益。
多測,
4s
題解
首先這是個“最大獲利”(學名 最大權閉合圖),可以快速建出模型:左邊 個點表示攝像頭,與源點相連,容量爲 ;右邊 個點表示樹上結點,與匯點相連,容量爲 ,然後每個攝像頭與它監控的所有結點連邊,容量爲 。跑最小割即是答案。
然後這個圖太大了,所以要考慮用貪心模擬網絡流。
對於每個點上的攝像頭,它的最優方案肯定是先找深度最大的結點來流。因此可以每個點維護一個 set,存這棵子樹下每個深度的剩餘流量。然後攝像頭就貪心地在 set 裏找深度最大的去流。
然後 set 裏的內容是以深度爲下標的,因此用長鏈剖分來合併,這樣就是 的了。
代碼
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,LL> spr;
const int maxn=3e5+5;
const LL inf=1e18;
int n,m,a[maxn];
vector<int> e[maxn];
vector<pair<int,int>> q[maxn];
int maxdeep[maxn],Lson[maxn],deep[maxn];
void dfs_pre(int k,int last)
{
Lson[k]=0;
maxdeep[k]=deep[k]=deep[last]+1;
for(int go:e[k])
{
dfs_pre(go,k);
if (maxdeep[go]>maxdeep[Lson[k]]) Lson[k]=go;
}
}
LL ans;
set<spr> S[maxn];
int id[maxn];
void merge(int a,int b)
{
for(spr pr:S[b])
{
set<spr>::iterator it=S[a].upper_bound(make_pair(pr.fi,inf));
if (it==S[a].begin()) continue;
it--;
if (it->fi==pr.fi)
{
spr now=*it; S[a].erase(now);
now.se+=pr.se;
S[a].insert(now);
} else S[a].insert(pr);
}
S[b].clear();
}
void calc(int k)
{
for(pair<int,int> qi:q[k])
{
while (qi.se>0)
{
set<spr>::iterator it=S[id[k]].upper_bound(make_pair(qi.fi+deep[k],inf));
if (it==S[id[k]].begin()) break;
it--;
spr now=*it; S[id[k]].erase(now);
LL nmin=min(now.se,1ll*qi.se);
ans-=nmin;
qi.se-=nmin;
now.se-=nmin;
if (now.se>0) S[id[k]].insert(now);
}
}
}
void dfs(int k)
{
if (!Lson[k])
{
S[k].insert(make_pair(deep[k],a[k]));
calc(k);
return;
}
dfs(Lson[k]);
id[k]=id[Lson[k]];
S[id[k]].insert(make_pair(deep[k],a[k]));
for(int go:e[k]) if (go!=Lson[k])
{
dfs(go);
merge(id[k],id[go]);
}
calc(k);
}
void Clear()
{
fo(i,1,n)
{
e[i].clear(), q[i].clear(), S[i].clear();
id[i]=i;
}
ans=0;
}
int T;
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d %d",&n,&m);
Clear();
fo(i,2,n)
{
int x;
scanf("%d",&x);
e[x].push_back(i);
}
fo(i,1,n) scanf("%d",&a[i]), ans+=a[i];
fo(i,1,m)
{
int x,k,c;
scanf("%d %d %d",&x,&k,&c);
q[x].push_back(make_pair(k,c));
}
dfs_pre(1,0);
dfs(1);
printf("%lld\n",ans);
}
}