NOIP模擬 戰爭(反向建圖+並查集)
阿新 • • 發佈:2018-12-17
QAQ
【題目分析】
好菜好菜。。。。。fAKe dalao ldx差點就AK了啊。。。。。。。再看看自己的分。。。。。【捂臉】
之前還做過同類型的題啊,藍瘦。
正難則反,既然刪點難以維護,就考慮向圖中加點,直接離線處理。
首先讀入所有操作,統計最後剩下的所有點產生的貢獻,合併兩個聯通塊產生的貢獻就是兩個聯通塊的權值和的積,所以維護一下就好了,至於每次摧毀的點要記得連通後要變成未摧毀的,調了半天。。。。。
【程式碼~】
#include<bits/stdc++.h> using namespace std; typedef long long LL; const LL MAXN=1e6+10; const LL MOD=1e9+7; LL n,m,cnt,ans[MAXN]; LL vis[MAXN],des[MAXN],sum; LL head[MAXN],to[MAXN<<1],nxt[MAXN<<1]; vector<LL> tim[MAXN]; struct father{ LL fat,sum; }fa[MAXN]; LL Read() { LL i=0,f=1; char c; for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar()); if(c=='-') f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar()) i=(i<<3)+(i<<1)+c-'0'; return i*f; } void sc(LL x) { if(x>=10) sc(x/10); putchar(x%10+48); } void add(LL x,LL y) { nxt[cnt]=head[x]; head[x]=cnt; to[cnt]=y; cnt++; } LL find(LL x) { if(x==fa[x].fat) return x; return fa[x].fat=find(fa[x].fat); } void merge(LL x,LL y) { sum=(sum+fa[x].sum*fa[y].sum%MOD)%MOD; fa[x].sum=(fa[x].sum+fa[y].sum)%MOD; fa[y].fat=x; } void dfs(LL u) { vis[u]=1; for(LL i=head[u];i!=-1;i=nxt[i]) { LL v=to[i]; if(!vis[v]&&!des[v]) { LL x=find(u),y=find(v); merge(x,y); dfs(v); } } } void addpoint(LL u) { des[u]=0; for(LL i=head[u];i!=-1;i=nxt[i]) { LL v=to[i]; if(!des[v]) { LL x=find(u),y=find(v); merge(x,y); } } } int main() { memset(head,-1,sizeof(head)); n=Read(),m=Read(); for(LL i=2;i<=n;++i) { LL fath=Read(); add(i,fath); add(fath,i); } for(LL i=1;i<=n;++i) fa[i].fat=fa[i].sum=i; for(LL i=1;i<=m;++i) { LL total=Read(); for(LL j=1;j<=total;++j) { LL id=Read(); des[id]=1; tim[i].push_back(id); } } for(LL i=1;i<=n;++i) if(!vis[i]&&!des[i]) dfs(i); ans[m]=sum; for(LL i=m;i;--i) { LL siz=tim[i].size(); for(LL j=0;j<siz;++j) addpoint(tim[i][j]); ans[i-1]=sum; } for(LL i=0;i<=m;++i) cout<<ans[i]<<'\n'; return 0; }