Codechef Sad Pairs——圆方树+虚树+树上差分
删点不连通,点双,圆方树
非割点:没有影响
割点:子树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——圆方树+虚树+树上差分的更多相关文章
- 仙人掌 && 圆方树 && 虚树 总结
仙人掌 && 圆方树 && 虚树 总结 Part1 仙人掌 定义 仙人掌是满足以下两个限制的图: 图完全联通. 不存在一条边处在两个环中. 其中第二个限制让仙人掌的题做 ...
- [SDOI2018]战略游戏(圆方树+虚树)
喜闻乐见的圆方树+虚树 图上不好做,先建出圆方树. 然后答案就是没被选到的且至少有两条边可以走到被选中的点的圆点的数量. 语文不好,但结论画画图即可得出. 然后套路建出虚树. 发现在虚树上DP可以得出 ...
- BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)
Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...
- BZOJ.5329.[SDOI2018]战略游戏(圆方树 虚树)
题目链接 显然先建圆方树,方点权值为0圆点权值为1,两点间的答案就是路径权值和减去起点终点. 对于询问,显然可以建虚树.但是只需要计算两关键点间路径权值,所以不需要建出虚树.统计DFS序相邻的两关键点 ...
- UOJ.87.mx的仙人掌(圆方树 虚树)(未AC)
题目链接 本代码10分(感觉速度还行..). 建圆方树,预处理一些东西.对询问建虚树. 对于虚树上的圆点直接做:对于方点特判,枚举其所有儿子,如果子节点不在该方点代表的环中,跳到那个点并更新其val, ...
- 洛谷P4606 [SDOI2018]战略游戏 【圆方树 + 虚树】
题目链接 洛谷P4606 双倍经验:弱化版 题解 两点之间必经的点就是圆方树上两点之间的圆点 所以只需建出圆方树 每次询问建出虚树,统计一下虚树边上有多少圆点即可 还要讨论一下经不经过根\(1\)的情 ...
- P4606-[SDOI2018]战略游戏【圆方树,虚树】
正题 题目链接:https://www.luogu.com.cn/problem/P4606 题目大意 给出\(n\)个点\(m\)条边的一张图,\(q\)次询问给出一个点集,询问有多少个点割掉后可以 ...
- 洛谷4606 SDOI2018战略游戏(圆方树+虚树)
QWQ深受其害 当时在现场是真的绝望...... 现在再重新来看这个题 QWQ 根据题目所说,我们可以发现,对于每一个集合中的节点,我们实际上就是要求两两路径上的割点的数目 考虑到又是关于点双的题目, ...
- Luogu P4606 [SDOI2018] 战略游戏 圆方树 虚树
https://www.luogu.org/problemnew/show/P4606 把原来的图的点双联通分量缩点(每个双联通分量建一个点,每个割点再建一个点)(用符合逻辑的方式)建一棵树(我最开始 ...
随机推荐
- 20155227《网络对抗》Exp2 后门原理与实践
20155227<网络对抗>Exp2 后门原理与实践 基础问题回答 (1)例举你能想到的一个后门进入到你系统中的可能方式? 在非官方网站下载软件时,后门很可能被捆绑在软件中. 攻击者利用欺 ...
- wordpress必装的插件 wp最常用的十个插件
wordpress是世界上著名的博客系统,简称wp.一般新安装完wordpress以后,往往需要首先安装一些插件,这样才可以使用wordpress的更多功能.wp最常用的十个插件有哪些呢,可能根据每个 ...
- kvm虚拟化一: 图形化的管理方式
1.安装必要工具yum install -y / qemu-kvm //kvm主程序 libvirt //虚拟化服务库 libguestfs-tools //虚拟机系统管理工具 virt-instal ...
- CF 55 D. Beautiful numbers
D. Beautiful numbers 链接 题意: 求[L,R]中多少个数字可以整除它们的每一位上的数字. 分析: 要求模一些数字等于0等价于模它们的lcm等于0,所以可以记录当前出现的数字的lc ...
- [BZOJ4722]由乃[鸽巢原理+bitset+倍增]
题意 给定长为 \(n\) 序列 \(a\) ,要求支持两种操作: \(1.\) 询问在一个区间 \([l,r]\) 中,是否能够选出两个交集为空的集合 $ \rm X ,Y$, 使得 \(\sum_ ...
- Sterling B2B Integrator与SAP交互 - 01 简介
公司近期实施上线了SAP系统,由于在和客户的数据交互中采用了较多的EDI数据交换,且多数客户所采用的EDI数据并不太相同(CSV,XML,X12,WebService),所以在EDI架构上选择了IBM ...
- Linux Mint安装Docker踩坑指南
我家的服务器选用的Linux Mint系统,最近安装Docker的时候踩了一些小坑,但是总体还算顺利. 我们都知道Linux Mint系统是基于Ubuntu的,说实话用起来感觉还是很不错的,安装Doc ...
- 【转】Cocos2d-x 3.x基础学习: 总结数学类Vec2/Size/Rect
转载:http://www.taikr.com/article/1847 在Cocos2d-x 3.x中,数学类Vec2.Size.Rect,是比较常用的类.比如设置图片位置,图片大小,两图片的碰撞检 ...
- Assetbundle管理与加载
最近在做项目优化的时候发现公司的项目用的还是老式的WWW去加载assetbundle资源的形式,而且是通过在两个Update里面分开加载AB和Asset的,这样虽然避免了协程的的使用,但是把一件事分开 ...
- Notes of Daily Scrum Meeting(12.18)
前期落下的进度我们会在周六周日赶一下,在编译课程设计中期测试之后集中处理项目中的问题. 今天的任务总结如下: 团队成员 今日团队工作 陈少杰 调试后端连接的部分,寻找bug 王迪 测试搜索功能,修改b ...