删点不连通,点双,圆方树
非割点:没有影响
割点:子树DP一下
有不同颜色,所以建立虚树
在圆方树上dfs时候
如果当前点是割点
1.统计当前颜色虚树上的不连通点对,树形DP即可
2.统计所有颜色的虚树上的不连通点对。。。。
一个麻烦事是,虚树上一条边上选择一个原树割点,都会对这个虚树造成相同的影响(两边sz乘积)
n,m 2e5
树上差分
设虚树上,(x,y)的边,x是y的父亲
原树上,x的位置减去贡献,y的原树father位置加上贡献
最后dfs扫一遍就行了。
实际上麻烦事挺多:
1.不保证连通,所以圆方树森林,虚树森林
2.LCA可能是多个颜色虚树的节点,dp[x]是累计的
3.x断线只有的ans:原来本身不连通的+经过x的+x和同种别的颜色 (后面两个都是自己连通块内部)
错点:
1.dfn的cmp没有写进sort函数
2.vis在dfs时候没有赋值导致循环多遍
3.存在孤立点,不在任意一个DCC中,赋值typ=1的时候,特殊考虑到(其实typ=1没有意义)
4.统计的是当前连通块当前颜色的数量,所以初值:sz[x]=(co[x]==now)
5.答案爆int。两块sz相乘也会爆int
代码:
#include<bits/stdc++.h> #define il inline #define reg register int #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=4e5+5; int n,m; int a[N][2]; int kind;//species struct node{ int nxt,to; }e[2*N]; int hd[N],cnt; void add(int x,int y){ e[++cnt].nxt=hd[x]; e[cnt].to=y; hd[x]=cnt; } int dfn[N],low[N],df,dfn2[N]; int co[N],b[N],dcc; vector<int>mem[N]; ll preno; vector<int>be[N]; int typ[N];//1:yuan 0:fang int sta[N],top; void tarjan(int x){ dfn[x]=low[x]=++df; sta[++top]=x; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]){ ++dcc; int z; do{ z=sta[top]; mem[dcc].push_back(z); --top; }while(z!=y); mem[dcc].push_back(x); } }else low[x]=min(low[x],dfn[y]); } } int belong[N]; int dep[N],fa[N][20]; void dfs1(int x,int bl,int d){ belong[x]=bl; dfn[x]=++df; dep[x]=d; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(!dfn[y]){ fa[y][0]=x; dfs1(y,bl,d+1); } } dfn2[x]=df; } ll dp[N]; ll tag[N]; int vis[N]; ll sz[N]; void finsz(int x,int now){ vis[x]=now+kind; sz[x]=(co[x]==now); for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; finsz(y,now); sz[x]+=sz[y]; } } void dfs2(int x,ll totsz,int now){ // cout<<" dfs2 "<<x<<" : "<<totsz<<" "<<now<<endl; ll presz=0; //dp[x]=0; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; dfs2(y,totsz,now); tag[x]-=(totsz-sz[y])*sz[y]; //cout<<" fa[y][0] "<<fa[y][0]<<endl; tag[fa[y][0]]+=(totsz-sz[y])*sz[y]; dp[x]+=presz*sz[y]; presz+=sz[y]; } dp[x]+=presz*(totsz-sz[x]); if(co[x]==now)dp[x]+=totsz-typ[x]; } ll ans[N]; void sol(int x,int fa){ vis[x]=1; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa) continue; sol(y,x); tag[x]+=tag[y]; } //cout<<" x "<<x<<" : "<<preno+dp[x]+tag[x]<<endl; if(typ[x]) ans[x]=preno+dp[x]+tag[x]; } bool cmp(int x,int y){ return dfn[x]<dfn[y]; } int lca(int x,int y){ if(dep[x]<dep[y]) swap(x,y); for(reg j=19;j>=0;--j){ if(dep[fa[x][j]]>=dep[y]) x=fa[x][j]; } if(x==y) return x; for(reg j=19;j>=0;--j){ if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; } return fa[x][0]; } int main(){ rd(n);rd(m); int tot=0; for(reg i=1;i<=n;++i) rd(co[i]),b[++tot]=co[i]; sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-b-1; kind=tot; for(reg i=1;i<=n;++i){ typ[i]=1; co[i]=lower_bound(b+1,b+tot+1,co[i])-b; //cout<<co[i]<<" "; be[co[i]].push_back(i); } // cout<<endl; int x,y; for(reg i=1;i<=m;++i){ rd(x);rd(y);add(x,y);add(y,x); } for(reg i=1;i<=n;++i){ if(!dfn[i]) tarjan(i); } memset(hd,0,sizeof hd); memset(dfn,0,sizeof dfn); df=0;cnt=0; tot=n; int edge=0; //cout<<" dcc "<<dcc<<endl; for(reg i=1;i<=dcc;++i){ ++tot; typ[tot]=0; //cout<<"num ******************"<<tot<<endl; for(reg j=0;j<(int)mem[i].size();++j){ // cout<<mem[i][j]<<" "; typ[mem[i][j]]=1; a[++edge][0]=tot; a[edge][1]=mem[i][j]; add(tot,mem[i][j]); add(mem[i][j],tot); } //cout<<endl; } // cout<<" tot "<<tot<<endl; int kuai=0; for(reg i=1;i<=tot;++i){ if(!dfn[i]){ dfs1(i,++kuai,1); } } // cout<<" kuai "<<kuai<<endl; memset(hd,0,sizeof hd); cnt=0; for(reg j=1;j<=19;++j){ for(reg i=1;i<=n;++i){ fa[i][j]=fa[fa[i][j-1]][j-1]; } } for(reg i=1;i<=kind;++i){ //cout<<" kind i "<<i<<" ------------------------------- "<<endl; int num=be[i].size(); sort(be[i].begin(),be[i].end(),cmp); for(reg j=1;j<num;++j){ vis[be[i][j]]=vis[be[i][j-1]]=i; if(belong[be[i][j]]==belong[be[i][j-1]]){ int anc=lca(be[i][j],be[i][j-1]); if(vis[anc]!=i){ vis[anc]=i; be[i].push_back(anc); } } } sort(be[i].begin(),be[i].end(),cmp); top=0; for(reg j=0;j<(int)be[i].size();++j){ // cout<<" j "<<be[i][j]<<endl; while(top&&(!(dfn[sta[top]]<=dfn[be[i][j]]&&dfn[be[i][j]]<=dfn2[sta[top]])))--top; if(top) add(sta[top],be[i][j]); sta[++top]=be[i][j]; } ll has=0; for(reg j=0;j<(int)be[i].size();++j){ if(vis[be[i][j]]!=i+kind){ finsz(be[i][j],i); // cout<<" totsz "<<be[i][j]<<" "<<typ[be[i][j]]<<" "<<sz[be[i][j]]<<endl; dfs2(be[i][j],sz[be[i][j]],i); preno+=has*sz[be[i][j]]; has+=sz[be[i][j]]; } } for(reg j=0;j<(int)be[i].size();++j){ hd[be[i][j]]=0; sz[be[i][j]]=0; } cnt=0; } // cout<<" preno "<<preno<<endl; // for(reg i=1;i<=tot;++i){ // printf("%d dp %lld %lld ",i,dp[i],tag[i]); // } memset(vis,0,sizeof vis); for(reg i=1;i<=edge;++i){ add(a[i][0],a[i][1]); add(a[i][1],a[i][0]); } for(reg i=1;i<=tot;++i){ if(!vis[i]){ sol(i,0); } } for(reg i=1;i<=n;++i){ printf("%lld ",ans[i]); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/2/19 17:48:21 */