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 把原来的图的点双联通分量缩点(每个双联通分量建一个点,每个割点再建一个点)(用符合逻辑的方式)建一棵树(我最开始 ...
随机推荐
- [BZOJ4842]Delight for a Cat[费用流]
题意 题目链接 分析 类似 最长k可重区间集 一题. 由于本题区间长度相同,首先可以将点的影响看成区间,区间看成点. 先默认所有位置选择事件2,选择区间看做改选事件1 .于是问题变成了求收益最大的方案 ...
- PowerBI开发 第五篇:关系和交互
PowerBI 使用 内存的列式数据库 VertiPaq,用于对已发布的数据集进行数据压缩和快速处理,能够使PowerBI报表执行脱机访问,面向列的处理,高度优化对1:N关系的处理性能.关系是数据分析 ...
- [Mark]Tomcat/IIS 更改 HTTP 侦听端口
目的: IIS HTTP 侦听端口改为 8088 Tomcat HTTP 侦听端口改为 80 环境: Windows Server 2012 R2 IIS8.5 (默认端口是 80) Tomcat8. ...
- REST-framework快速构建API--频率
前面已经了解了API的认证和授权.认证,是对资源访问者的第一道门,必须有钥匙,你才能进来拿我的资源:授权,是对资源访问者的第二道门,虽然你进来了,但是你可以拿走什么资源,还是我说了算,就是授权. 当然 ...
- docker 部署Spring Boot:Docker化Spring Boot应用程序
第一章 1.创建项目存放目录 mkdir /root/sproot -p 2.准备好Spring Boot应用程序 jar 包 testrest.jar 第二章 1. 安装docker 在所有节点执行 ...
- Siki_Unity_2-9_C#高级教程(未完)
Unity 2-9 C#高级教程 任务1:字符串和正则表达式任务1-1&1-2:字符串类string System.String类(string为别名) 注:string创建的字符串是不可变的 ...
- 【独家】K8S漏洞报告|近期bug fix解读&1.11主要bug fix汇总
内容提要: 1. 高危漏洞CVE-2018-1002105深度解读 2. 11/19--12/11 bug fix汇总分析 3. 1.11重要bug fix解读 4. 1.9重要bug fix解读 在 ...
- 一篇带你读懂TCP之“滑动窗口”协议
前言 你现在的努力,是为了以后有更多的选择. 在上一篇文章通过"表白"方式,让我们快速了解网络七层协议了解了网络七层协议. 接下来我们要把重心放在网络传输的可靠性上面.一起来看TC ...
- 实验---反汇编一个简单的C程序(杨光)
反汇编一个简单的C程序 攥写人:杨光 学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163 ...
- 第三周 构造一个简单的Linux系统MenuOS
一. Linux内核源代码简介 稳定版内核:Linux-3.18.6 Linux内核源代码的目录结构: arch目录:在Linux内核源代码里占有的比重很大,因为Linux内核支持很多的体系结构, ...