SADPAIRS

删点不连通,点双,圆方树

非割点:没有影响

割点:子树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*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=4e5+;
int n,m;
int a[N][];
int kind;//species
struct node{
int nxt,to;
}e[*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][];
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][]=x;
dfs1(y,bl,d+);
}
}
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=;
//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][]]+=(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]=;
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=;j>=;--j){
if(dep[fa[x][j]]>=dep[y]) x=fa[x][j];
}
if(x==y) return x;
for(reg j=;j>=;--j){
if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
}
return fa[x][];
}
int main(){
rd(n);rd(m);
int tot=;
for(reg i=;i<=n;++i) rd(co[i]),b[++tot]=co[i];
sort(b+,b+tot+);
tot=unique(b+,b+tot+)-b-;
kind=tot;
for(reg i=;i<=n;++i){
typ[i]=; co[i]=lower_bound(b+,b+tot+,co[i])-b;
//cout<<co[i]<<" ";
be[co[i]].push_back(i);
}
// cout<<endl; int x,y;
for(reg i=;i<=m;++i){
rd(x);rd(y);add(x,y);add(y,x);
} for(reg i=;i<=n;++i){
if(!dfn[i]) tarjan(i);
}
memset(hd,,sizeof hd);
memset(dfn,,sizeof dfn);
df=;cnt=;
tot=n;
int edge=;
//cout<<" dcc "<<dcc<<endl;
for(reg i=;i<=dcc;++i){
++tot;
typ[tot]=;
//cout<<"num ******************"<<tot<<endl;
for(reg j=;j<(int)mem[i].size();++j){
// cout<<mem[i][j]<<" ";
typ[mem[i][j]]=;
a[++edge][]=tot;
a[edge][]=mem[i][j];
add(tot,mem[i][j]);
add(mem[i][j],tot);
}
//cout<<endl;
}
// cout<<" tot "<<tot<<endl;
int kuai=;
for(reg i=;i<=tot;++i){
if(!dfn[i]){
dfs1(i,++kuai,);
}
}
// cout<<" kuai "<<kuai<<endl;
memset(hd,,sizeof hd);
cnt=; for(reg j=;j<=;++j){
for(reg i=;i<=n;++i){
fa[i][j]=fa[fa[i][j-]][j-];
}
}
for(reg i=;i<=kind;++i){
//cout<<" kind i "<<i<<" ------------------------------- "<<endl;
int num=be[i].size();
sort(be[i].begin(),be[i].end(),cmp);
for(reg j=;j<num;++j){
vis[be[i][j]]=vis[be[i][j-]]=i;
if(belong[be[i][j]]==belong[be[i][j-]]){
int anc=lca(be[i][j],be[i][j-]);
if(vis[anc]!=i){
vis[anc]=i;
be[i].push_back(anc);
}
}
}
sort(be[i].begin(),be[i].end(),cmp);
top=; for(reg j=;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=;
for(reg j=;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=;j<(int)be[i].size();++j){
hd[be[i][j]]=;
sz[be[i][j]]=;
}
cnt=;
}
// cout<<" preno "<<preno<<endl;
// for(reg i=1;i<=tot;++i){
// printf("%d dp %lld %lld\n",i,dp[i],tag[i]);
// }
memset(vis,,sizeof vis);
for(reg i=;i<=edge;++i){
add(a[i][],a[i][]);
add(a[i][],a[i][]);
}
for(reg i=;i<=tot;++i){
if(!vis[i]){
sol(i,);
}
}
for(reg i=;i<=n;++i){
printf("%lld\n",ans[i]);
}
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2019/2/19 17:48:21
*/

Codechef Sad Pairs——圆方树+虚树+树上差分的更多相关文章

  1. 仙人掌 && 圆方树 && 虚树 总结

    仙人掌 && 圆方树 && 虚树 总结 Part1 仙人掌 定义 仙人掌是满足以下两个限制的图: 图完全联通. 不存在一条边处在两个环中. 其中第二个限制让仙人掌的题做 ...

  2. [SDOI2018]战略游戏(圆方树+虚树)

    喜闻乐见的圆方树+虚树 图上不好做,先建出圆方树. 然后答案就是没被选到的且至少有两条边可以走到被选中的点的圆点的数量. 语文不好,但结论画画图即可得出. 然后套路建出虚树. 发现在虚树上DP可以得出 ...

  3. BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  4. BZOJ.5329.[SDOI2018]战略游戏(圆方树 虚树)

    题目链接 显然先建圆方树,方点权值为0圆点权值为1,两点间的答案就是路径权值和减去起点终点. 对于询问,显然可以建虚树.但是只需要计算两关键点间路径权值,所以不需要建出虚树.统计DFS序相邻的两关键点 ...

  5. UOJ.87.mx的仙人掌(圆方树 虚树)(未AC)

    题目链接 本代码10分(感觉速度还行..). 建圆方树,预处理一些东西.对询问建虚树. 对于虚树上的圆点直接做:对于方点特判,枚举其所有儿子,如果子节点不在该方点代表的环中,跳到那个点并更新其val, ...

  6. 洛谷P4606 [SDOI2018]战略游戏 【圆方树 + 虚树】

    题目链接 洛谷P4606 双倍经验:弱化版 题解 两点之间必经的点就是圆方树上两点之间的圆点 所以只需建出圆方树 每次询问建出虚树,统计一下虚树边上有多少圆点即可 还要讨论一下经不经过根\(1\)的情 ...

  7. P4606-[SDOI2018]战略游戏【圆方树,虚树】

    正题 题目链接:https://www.luogu.com.cn/problem/P4606 题目大意 给出\(n\)个点\(m\)条边的一张图,\(q\)次询问给出一个点集,询问有多少个点割掉后可以 ...

  8. 洛谷4606 SDOI2018战略游戏(圆方树+虚树)

    QWQ深受其害 当时在现场是真的绝望...... 现在再重新来看这个题 QWQ 根据题目所说,我们可以发现,对于每一个集合中的节点,我们实际上就是要求两两路径上的割点的数目 考虑到又是关于点双的题目, ...

  9. Luogu P4606 [SDOI2018] 战略游戏 圆方树 虚树

    https://www.luogu.org/problemnew/show/P4606 把原来的图的点双联通分量缩点(每个双联通分量建一个点,每个割点再建一个点)(用符合逻辑的方式)建一棵树(我最开始 ...

随机推荐

  1. 2017-2018-2 20155203《网络对抗技术》Exp5 MSF基础应用

    1.实践过程记录 1.1一个主动攻击实践,如ms08_067; msf > search ms08_067_netapi //查看可以用的工具 [!] Module database cache ...

  2. 【来龙去脉系列】AutoMapper一款自动映射框架

    前言 通常在一个应用程序中,我们开发人员会在两个不同的类型对象之间传输数据,通常我们会用DTOs(数据传输对象),View Models(视图模型),或者直接是一些从一个service或者Web AP ...

  3. Data Consistency Primer

    云应用通常来说,使用的数据很多都是分散的,来自不同的数据仓库.在这种环境下,管理和保持数据一致性是很复杂的,无论是在并发跟可用性上都可能出问题.开发者有的时候就需要为了强一致性而牺牲可用性了.这也就意 ...

  4. 一波三折Miz702终于能显示桌面上网啦

    先上两张图,总结之后再说啦---

  5. Yii2 软删除

    什么是软删除 后台操作,删除一条记录,不希望真正的从数据库中删除,用个字段标记一下.比如delete_at.默认0.当执行删除操作,更新delete_at为当前时间戳 这样列表显示的时候只查询dele ...

  6. 【中间件】Redis 实战之主从复制、高可用、分布式

    目录 简介 持久化 主从复制 高可用 Redis-Sentinel .NET Core开发 分布式 Redis-Cluster 配置说明 常见问题 简介 本节内容基于 CentOS 7.4.1708, ...

  7. [Latex] 所有字体embedded: Type3 PDF文档处理 / True Type转换为Type 1

    目录: [正文] Adobe Acrobat打印解决字体嵌入问题 [Appendix I] Type3转TRUE Type/Type 1 [Appendix II] TRUE Type转Type 1 ...

  8. 《杜增强讲Unity之Tanks坦克大战》10-相机控制

    10 相机控制 本节主要学习如何控制相机自动调整位置和焦距,使两个坦克一直同时在视野内.   image 在Hierarchy点击右键   image 点击 Create Empty,生成空对象,改名 ...

  9. ag使用需要注意的问题

    1.  set env 对比服务器标准配置,修改本地 /etc/apache2/sites-available/default (远程链接服务器的办法: ssh 12x.xxx.xxx.xxx) 2. ...

  10. alpha发布排序结果

    友组所做排序 其中有一组是教师排序. 序号 组名 组长 项目简称 匿名1组 匿名2组 匿名3组 匿名4组 匿名5组 匿名6组 匿名7组 匿名8组 平均 1 新蜂 武志远 俄罗斯 2 3 3 4 4 5 ...