1kri Round 1
为最近2月最大的工作做个总结
这是一种比较愚蠢的做法,它的 DP 过程太孬了。
题目较困难,考虑先通过结论和性质转化问题。
对于固定了黑白点的方案,我们考虑黑点集合。需要做的工作是把它划分为若干子集,每个子集用一条路径覆盖。结论1 :子集在原集合按 dfs 序排序后必然连续(证明:虚树的性质)。 那么现在我们相当于把黑点排好序,然后每次枚举区间到哪即可 DP 做到 \(O(n^2)\) 解决无灰点情况,这里区间的代价是 \(2\times \sum_{i\in [l,r]} \text{dep}_i-\max_{i\in [l,r]} \text{dep}_i\)。计数可以用 DP of DP 做到常数较大的 \(O(n^3)\) (?) 。
DP 看起来没有出路了,让我们来继续推性质。结论2:对于两个相邻区间 \([l_1,r_1],[l_2,r_2]\) ,如果其中设深度最大值分别为 \(m_1,m_2\) ,则 \(2\times \text{dep}(\text{LCA}(r_1,l_2)) \le \min(m_1,m_2)\) 是最优解的必要条件,如果再加上从前往后划分尽可能时划分点靠前或者说是能放就放的话,还是充分的。(证明:必要性显然,充分性是因为没有更新当前深度最大值的点没有贡献,更新后原来的值也没有贡献)。 这个结论很大胆,也很强,我们可以直接通过贪心来 \(O(n)\) 解决无灰点情况,同时也容易设计在 dfs 序上 DP 做到 \(O(n^3)\) 。具体的,设 \(f_{i,j}\) 作为方案数表示到了 \(i\) 这个点,若 \(j<0\) 表示当前区间深度最大值还小于上次间隔处限制,限制为 \(-j\) ;若 \(j>0\) 表示当前区间深度最大值不小于上次间隔处限制,最大值为 \(j\) (同时另有表示代价和的 DP 数组)。每次枚举下一个黑点在哪即可。如果优化转移可以做到 \(O(n^2)\) 或 \(O(n^2 \text{poly} \log)\) (?) 。
现在又没有出路了,我们不得不更换状态表示的范围。让我们弃暗投明,设 \(f_{i,j}\) 表示 \(i\) 子树内满足最后一段区间状态为 \(j\) 的方案数,若 \(j=0\) 即子树内无黑点。但是这样转换过来乍一眼不是适配的很好。结论3:DP 合并很简单。 让我们看到:1. 对于 \(x\) 上 \(j<0\) 如果在合并到 \(x\) 上的 \(v\) 子树中贪心地 DP 出来满足 \(j'<0 \or j'\ge 2\times \text{dep}_x\) 那么合并必然合法;2. 对于 \(x\) 上 \(j>0\) ,自然容易讨论出合并。类似树上背包,我们可以轻松做到 \(O(n^2)\) 。更优秀的,注意到合并 \(j,j'\) 时若 \(j' \neq 0\) 则只会转移到 \(j'\) 、\(-\text{dep}_x\) 或 \(\max(j,j')\) 同时系数也是方便转移的形式。那么利用线段树区间合并、区间打标记,我们容易把它优化到 \(O(n\log n)\) 。
不过,这种方法并不好写,而且空间顶多卡进 512 MB。\ll
写了两天。
\(\text{Code:}\)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define fi first
#define sc second
#define mkp make_pair
#define pii pair<int,int>
typedef long long ll;
const int N=2e5+5,oo=1e9,mod=1e9+7;
inline int read() {
int x=0,flag=0;char ch=getchar();
while(ch<'0'||ch>'9') {flag|=(ch=='-');ch=getchar();}
while('0'<=ch&&ch<='9') {x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return flag?-x:x;
}
inline int mx(int x,int y) {return x>y?x:y;}
inline int mn(int x,int y) {return x<y?x:y;}
inline void swp(int &x,int &y) {x^=y^=x^=y;}
inline int as(int x) {return x>0?x:-x;}
inline int ad(int x) {return x>=mod?x-mod:x;}
int n,a[N],hd[N],num,dep[N],ans;
struct node {
int nxt,to;
}e[N<<1];
#define v e[i].to
inline void adde(int x,int y) {
e[++num]=(node){hd[x],y};
hd[x]=num;
}
namespace sgt {
struct Node {
int lc,rc,S1,S2,S3,t1,t2,t3;
#define lc(now) w[now].lc
#define rc(now) w[now].rc
}w[N*100];
int rt[N],tot;
inline void pu(int now) {
w[now].S1=ad(w[lc(now)].S1+w[rc(now)].S1);
w[now].S2=ad(w[lc(now)].S2+w[rc(now)].S2);
w[now].S3=ad(w[lc(now)].S3+w[rc(now)].S3);
}
inline void MUL(int now,int t1,int t2,int t3) {
if(t1==1&&t2==1&&t3==0) return ;
w[now].S2=(1ll*w[now].S2*t2+1ll*w[now].S1*t3)%mod;
w[now].S1=1ll*w[now].S1*t1%mod;
w[now].S3=1ll*w[now].S3*t1%mod;
w[now].t3=(1ll*t2*w[now].t3+1ll*t3*w[now].t1)%mod;
w[now].t1=1ll*w[now].t1*t1%mod;
w[now].t2=1ll*w[now].t2*t2%mod;
}
inline void pd(int now) {
MUL(lc(now),w[now].t1,w[now].t2,w[now].t3);
MUL(rc(now),w[now].t1,w[now].t2,w[now].t3);
w[now].t1=w[now].t2=1;w[now].t3=0;
}
void update(int l,int r,int&now,int pos,int v1,int v2) {
if(!now) now=++tot,w[now].t1=w[now].t2=1,w[now].t3=0;
if(l==r) {w[now].S1=v1,w[now].S2=v2,w[now].S3=1ll*v1*(l+mod)%mod;return ;}
int mid=(l+r)>>1; pd(now);
if(pos<=mid) update(l,mid,lc(now),pos,v1,v2);
else update(mid+1,r,rc(now),pos,v1,v2);
pu(now);
}
void Update(int l,int r,int now,int x,int y,int t1,int t2,int t3) {
if(!now) return ;
if(x<=l&&r<=y) {
MUL(now,t1,t2,t3);
return ;
} int mid=(l+r)>>1; pd(now);
if(x<=mid) Update(l,mid,lc(now),x,y,t1,t2,t3);
if(y> mid) Update(mid+1,r,rc(now),x,y,t1,t2,t3);
pu(now);
}
pair<pii,int> query(int l,int r,int now,int x,int y) {
if(!now) return mkp(mkp(0,0),0);
if(x<=l&&r<=y) return mkp(mkp(w[now].S1,w[now].S2),w[now].S3);
int mid=(l+r)>>1; pd(now);
if(x<=mid) {
if(y>mid) {
pair<pii,int> v1=query(l,mid,lc(now),x,y),v2=query(mid+1,r,rc(now),x,y);
return mkp(mkp(ad(v1.fi.fi+v2.fi.fi),ad(v1.fi.sc+v2.fi.sc)),ad(v1.sc+v2.sc));
} else return query(l,mid,lc(now),x,y);
} else return query(mid+1,r,rc(now),x,y);
}
int S1,S1_,S2,S2_,p1,p2,op;
int merge(int l,int r,int x,int y,int L,int R) {
int mid=(l+r)>>1,now=++tot;w[now].t1=w[now].t2=1,w[now].t3=0;
if(L<=l&&r<=R) {
if(!x) {
w[now]=w[y];
S2=ad(S2+w[now].S1);S2_=ad(S2_+w[now].S2);
MUL(now,S1,S1,(S1_+1ll*op*(S1-p1+mod))%mod);
return now;
}
if(!y) {
w[now]=w[x];
S1=ad(S1+w[now].S1)%mod;S1_=ad(S1_+w[now].S2);
MUL(now,S2,S2,(S2_+1ll*op*(S2-p2+mod))%mod);
return now;
}
if(l==r) {
w[now].S1=(1ll*S1*w[y].S1+1ll*S2*w[x].S1+1ll*w[x].S1*w[y].S1)%mod;
w[now].S2=(1ll*S1*w[y].S2+1ll*S1_*w[y].S1+1ll*S2*w[x].S2+1ll*S2_*w[x].S1
+1ll*w[x].S1*w[y].S2+1ll*w[x].S2*w[y].S1)%mod;
w[now].S3=1ll*(l+mod)*w[now].S1%mod;
if(l)w[now].S2=(w[now].S2+1ll*op*w[y].S1%mod*(S1-p1+mod))%mod;
S1=(S1+w[x].S1)%mod;S1_=(S1_+w[x].S2)%mod;
S2=(S2+w[y].S1)%mod;S2_=(S2_+w[y].S2)%mod;
if(l)w[now].S2=(w[now].S2+1ll*op*w[x].S1%mod*(S2-p2+mod))%mod;
return now;
}
} pd(x); pd(y);
if(L<=mid) lc(now)=merge(l,mid,lc(x),lc(y),L,R);
if(R> mid) rc(now)=merge(mid+1,r,rc(x),rc(y),L,R);
pu(now); return now;
}
int merge_(int l,int r,int x,int L,int R,int V) {
if(!x) return 0;
if(L<=l&&r<=R) return 0;
if(l>R||r<L) {MUL(x,V,V,0);return x;}
int mid=(l+r)>>1; pd(x);
lc(x)=merge_(l,mid,lc(x),L,R,V);
rc(x)=merge_(mid+1,r,rc(x),L,R,V);
pu(x); return x;
}
int Merge(int l,int r,int x,int y) {
if(!x||!y) return x|y;
if(0<=l&&r<=p1) return x;
if(l==r) {
w[x].S1=ad(w[x].S1+w[y].S1);
w[x].S2=ad(w[x].S2+w[y].S2);
w[x].S3=1ll*w[x].S1*(l+mod)%mod;
return x;
}
int mid=(l+r)>>1; pd(x);pd(y);
lc(x)=Merge(l,mid,lc(x),lc(y));
rc(x)=Merge(mid+1,r,rc(x),rc(y));
pu(x);
return x;
}
void print(int l,int r,int now) {
if(!now) return ;
if(l==r) {
if(l>=0) ans=(ans+w[now].S2-1ll*l*w[now].S1%mod+mod)%mod;
else ans=(ans+w[now].S2+2ll*l*w[now].S1%mod+mod)%mod;
return ;
}
int mid=(l+r)>>1; pd(now);
print(l,mid,lc(now));print(mid+1,r,rc(now));
}
}using namespace sgt;
void dfs(int x,int fa) {
dep[x]=dep[fa]+1;
if(a[x]!=0) update(-n,n,rt[x],dep[x],1,2*dep[x]);
if(a[x]!=1) update(-n,n,rt[x],0,1,0);
for(int i=hd[x],tmp,now,Now,s1,s2;i;i=e[i].nxt) {
if(v==fa) continue;
dfs(v,x);
pair<pii,int> ovo=query(-n,n,rt[x],-n,-1);
pair<pii,int> uou=query(-n,n,rt[x],0,0);
pair<pii,int> qwq=(dep[x]?query(-n,n,rt[x],1,mn(2*dep[x]-1,n)):mkp(mkp(0,0),0));
pair<pii,int> qaq=(2*dep[x]<=n?query(-n,n,rt[x],2*dep[x],n):mkp(mkp(0,0),0));
pair<pii,int> mwr=(dep[x]?query(-n,n,rt[v],1,2*dep[x]-1):mkp(mkp(0,0),0));
pair<pii,int> slh=query(-n,n,rt[v],0,0);
tmp=0; s1=w[rt[x]].S1,s2=w[rt[x]].S2;
if(x!=1) {
S1=S2=S1_=S2_=0;
p1=uou.fi.fi;p2=slh.fi.fi;op=(mod-2*dep[x])%mod;
tmp=merge(-n,n,rt[x],rt[v],0,2*dep[x]-1);
p1=-1; tmp=Merge(-n,n,tmp,merge_(-n,n,rt[x],0,mn(2*dep[x]-1,n),slh.fi.fi));
}
now=(s2+2ll*ovo.sc)%mod;
now=(now-qaq.sc+mod)%mod;
now=(now-2ll*dep[x]*qwq.fi.fi%mod+mod)%mod;
Update(-n,n,rt[v],-n,-1,s1,s1,now);
if(2*dep[x]<=n) Update(-n,n,rt[v],2*dep[x],n,s1,s1,now);
if(x!=1) {
now=(1ll*ovo.fi.sc*mwr.fi.fi+1ll*ovo.fi.fi*mwr.fi.sc)%mod;
now=(now+2ll*ovo.sc*mwr.fi.fi)%mod;
Now=(1ll*qaq.fi.sc*mwr.fi.fi+1ll*qaq.fi.fi*mwr.fi.sc)%mod;
Now=(Now-1ll*qaq.sc*mwr.fi.fi%mod+mod)%mod;
s1=1ll*mwr.fi.fi*(ovo.fi.fi+qaq.fi.fi)%mod;s2=(now+Now)%mod;
if(s1||s2) update(-n,n,rt[v],-dep[x],s1,s2);
}
p1=2*dep[x]-1;
rt[x]=Merge(-n,n,tmp,rt[v]);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1,x,y;i<n;++i) {
x=read();y=read();
adde(x,y);adde(y,x);
}
dep[0]=-1;
dfs(1,0);
print(-n,n,rt[1]);
if(a[1]==-1) printf("%d\n",2*ans%mod);
else printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号