2018.10.23【校內模擬】戰爭(並查集)
阿新 • • 發佈:2018-12-17
傳送門
解析:
首先,順序刪邊維護連通性其實就是倒著把所有點加回去就行了。
同時並查集維護一下當前連通塊權值之和。
每次合併得到的新增的貢獻就是兩個連通塊權值的乘積。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit( c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline void outint(ll a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=1000006;
cs ll mod=1000000007;
struct edge{
int u,v,tim;
friend bool operator <(cs edge &a,cs edge &b){
return a.tim<b.tim;
}
}e[N];
int del[N];
int fa[N];
ll val[N];
inline int getfa(int x){
while(x^fa[x])x=fa[x]=fa[fa[x]];
return x;
}
ll now;
inline void merge(int u,int v){
u=getfa(u);
v=getfa(v);
if(u==v)return ;
fa[v]=u;
now=(now+val[u]*val[v])%mod;
val[u]=(val[u]+val[v])%mod;
}
ll ans[N];
int n,m;
signed main(){
n=getint();
m=getint();
for(int re i=1;i<n;++i){
e[i].u=i+1;
e[i].v=getint();
}
for(int re i=1;i<=n;++i)val[i]=i,fa[i]=i;
memset(del,0x3f,sizeof del);
for(int re i=1;i<=m;++i){
int k=getint();
while(k--){
int u=getint();
del[u]=i;
}
}
for(int re i=1;i<n;++i)e[i].tim=min(del[e[i].u],del[e[i].v]);
sort(e+1,e+n);
int k=n-1;
for(int re i=m+1;i;--i){
while(e[k].tim>=i)
merge(e[k].u,e[k].v),--k;
ans[i]=now;
}
for(int re i=1;i<=m+1;++i)outint(ans[i]),pc('\n');
return 0;
}