题意
题解
虽然在\(RMQ\)的章节里,但是这题的重点不在\(RMQ\),只是一个优化
考虑如何找到一段完美序列
记录\(lst[val]\)表示val值上次出现的位置,\(pre[i]\)表示以\(i\)为结尾的完美序列的起点
那么转移式很显然
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 2e5+10;
inline ll read()
{
ll ret=0;char ch=' ',c=getchar();
while(!(c>='0'&&c<='9')) ch=c,c=getchar();
while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
return ch=='-'?-ret:ret;
}
int n,w[N],ecnt=-1,head[N],minw=INF,du[N];
ll ans;
struct edge
{
int nxt,to;
}a[N<<1];
inline void add(int x,int y)
{
a[++ecnt]=(edge){head[x],y};
head[x]=ecnt;
}
void dfs(int u,int fa)
{
if(!w[u]) return;
minw=min(minw,w[u]);
for(int i=head[u];~i;i=a[i].nxt)
{
int v=a[i].to;
if(v==fa||!w[v]) continue;
dfs(v,u);
break;
}
w[u]-=minw;
if(w[u]==0)
for(int i=head[u];~i;i=a[i].nxt)
{
int v=a[i].to;
du[v]--;
}
}
int main()
{
freopen("snow.in","r",stdin);
freopen("snow.out","w",stdout);
memset(head,-1,sizeof(head));
n=read();
for(int i=1;i<=n;i++) w[i]=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
add(u,v),add(v,u);
du[u]++,du[v]++;
}
while(1)
{
//printf("1");
minw=INF;
bool flag=0;
for(int i=1;i<=n;i++)
{
if(w[i]&&du[i]<=1)
{
flag=1,dfs(i,0),ans+=minw;
// printf("i=%d\n",i);
//for(int i=1;i<=n;i++)
// printf("w[%d]=%d\n",i,w[i]);
}
}
if(!flag) break;
}
printf("%lld",ans);
return 0;
}
/*
5
5 4 5 3 2
1 2
2 3
3 4
3 5
*/