[JZOJ100019]A--dfn序+扫描线

题目链接

太懒了自行搜索

分析

这道题查了一个下午的错,真的心态崩了

不过这道题确实妙啊

类比于喝喝喝,我们发现任何一条覆盖了非法路径的路径一定不合法,假如非法路径为\((x,kx)\),设\(u\)为\(dfn\)序中较小的那个点,\(v\)为较大的那个;假如覆盖了路径\((u,v)\)的路径为\((a,b)(dfn_a<dfn_b)\);

设数组\(ed[x]\)为\(x\)的子树中\(dfs\)最大的那个点的\(dfs\)序,显然这可以和\(dfs\)序在一遍\(dfs\)中求出

我们还需要知道:\(x\) 的子树中\(dfs\)序是连续的一段

考虑两种情况:

  • \(u\)是\(lca(u,v)\),分析发现这也有两种情况

    先设\(g\)为路径\((u,v)\)上距\(u\)最近的那个点

    • Case#1

      \(dfn[v]<=dfn[a]<=ed[v]\) , \(dfn[b]>ed[g]\)

    • Case#2

    \(dfn[v]<=dfn[b]<=ed[v]\) , \(dfn[g]>dfn[a]\)

  • \(u\)不是\(lca(u,v)\)

    这个只有一种情况,\(a,b\)分别在\(u,v\)子树中,即

    Case#3

    \(dfn[u]<=dfn[a]<=ed[u]<=dfn[v]<=dfn[b]<=ed[v]\)

我们把\((a,b)\)看成一个有序数对的话,发现其实每一种\(case\)都围成了一个矩形,我们只需要求出矩形面积的并之后即可得出所有不合法的路径,用总路径数\(n*(n-1)/2\)减去不合法即所求

求矩形面积的并使用线段树的扫描线法,但是发现一个点我们也要算进贡献,并非严格意义的二维图形;

因为值域很小\((1e5)\),学会了一种船新操作,我们不排序,将纵坐标相同的丢入一个容器,直接从小到大钦定纵坐标.不断取出对应容器内的线段加入,然后计算剩余的点数即可(纵坐标已钦定)

一道图论题转化成了数据结构,也是精妙啊

代码

/*
code by RyeCatcher
*/
inline char gc(){
static char buf[SIZE],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=500005;
const int inf=0x7fffffff;
int n;
struct Edge{
int ne,to;
}edge[maxn<<1];
int h[maxn],num_edge=1;
int fa[maxn][17];
inline void add_edge(int f,int to){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
h[f]=num_edge;
}
int dfn[maxn],ed[maxn],dep[maxn],tot=0;
void dfs(int now){
int v;dfn[now]=++tot;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa[now][0]||dfn[v])continue;
dep[v]=dep[now]+1,fa[v][0]=now;
for(ri i=1;i<=16;i++)fa[v][i]=fa[fa[v][i-1]][i-1];
dfs(v);
}
ed[now]=tot;
return ;
}
int get_g(int x,int y){//x到y路径上距y最近
for(ri i=16;i>=0;i--){
//printf("%d %d\n",fa[x][i],x);
if(dep[fa[x][i]]>dep[y]){
x=fa[x][i];
//printf("%d\n",x);
}
}
return x;
}
int L,R,dta;
struct Seg{
int l,r,h,d;
Seg(){l=r=h=d=0;}
Seg(int _l,int _r,int _h,int _d){l=_l,r=_r,h=_h,d=_d;}
}seg[maxn<<4];
int poi=0;
ll sum[maxn<<2];
ll tag[maxn<<2];
vector <int> dd[maxn];
inline void modify(int now,int l,int r){
if(tag[now]>0)sum[now]=(r-l+1);
else sum[now]=sum[now<<1]+sum[now<<1|1];
}
void update(int now,int l,int r){
if(L<=l&&r<=R){
tag[now]+=dta;
modify(now,l,r);
return ;
}
int mid=(l+r)>>1;
if(L<=mid)update(now<<1,l,mid);
if(mid<R)update(now<<1|1,mid+1,r);
modify(now,l,r);
return ;
}
ll ans=0;
int main(){
int x,y,ex,ey,g;
FO(a);
//freopen("a5.in","r",stdin);
read(n);
for(ri i=1;i<n;i++){
read(x),read(y);
add_edge(x,y);
add_edge(y,x);
}
dep[1]=1,fa[1][0]=0;
dfs(1);
int p,q;
for(ri i=1;i<=n;i++){
for(ri j=i+i;j<=n;j+=i){
p=i,q=j;
if(dfn[p]<dfn[q])swap(p,q);
x=dfn[p],y=dfn[q];
ex=ed[p],ey=ed[q];
if(x>=y&&x<=ey){
g=get_g(p,q);
dd[x].push_back(++poi);
seg[poi]=Seg(1,dfn[g]-1,x,1);
dd[ex+1].push_back(++poi);
seg[poi]=Seg(1,dfn[g]-1,ex,-1);
if(ed[g]==n)continue;
dd[ed[g]+1].push_back(++poi);
seg[poi]=Seg(x,ex,ed[g]+1,1);
dd[n+1].push_back(++poi);
seg[poi]=Seg(x,ex,n,-1);
}
else {
dd[x].push_back(++poi);
seg[poi]=Seg(y,ey,x,1);
dd[ex+1].push_back(++poi);
seg[poi]=Seg(y,ey,ex,-1);
}
}
}
for(ri i=1;i<=n;i++){
for(ri j=0;j<dd[i].size();j++){
x=dd[i][j];
L=seg[x].l,R=seg[x].r,dta=seg[x].d;
update(1,1,n);
}
ans+=sum[1];
}
printf("%lld\n",1ll*n*(n-1)/2-ans);
return 0;
}

[JZOJ100019]A--dfn序+扫描线的更多相关文章

  1. 洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)

    洛谷题目传送门 具体思路看别的题解吧.这里只提两个可能对常数和代码长度有优化的处理方法. I 把一个询问拆成\(9\)个甚至\(16\)个莫队询问实在是有点珂怕. 发现询问的一边要么是一个区间,要么是 ...

  2. 线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)

    闲话 stO猫锟学长,满脑子神仙DS 网上有不少Dalao把线段树分治也归入CDQ分治? 还是听听YCB巨佬的介绍: 狭义:只计算左边对右边的贡献. 广义:只计算外部对内部的贡献. 看来可以理解为广义 ...

  3. 洛谷P3703 [SDOI2017]树点涂色(LCT,dfn序,线段树,倍增LCA)

    洛谷题目传送门 闲话 这是所有LCT题目中的一个异类. 之所以认为是LCT题目,是因为本题思路的瓶颈就在于如何去维护同颜色的点的集合. 只不过做着做着,感觉后来的思路(dfn序,线段树,LCA)似乎要 ...

  4. Kattis - boxes (dfn序)

    Boxes There are N boxes, indexed by a number from 1 to N . Each box may (or not may not) be put into ...

  5. 树的遍历顺序 - dfs序|欧拉序|dfn序(备忘)

    (仅作备忘) dfs序是dfs过程中对于某节点进入这个节点的子树和离开子树的顺序 满足每个节点都会在dfs序上出现恰好两次 任意子树的dfs序都是连续的 欧拉序是dfs过程中经过节点的顺序 每个节点至 ...

  6. bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论

    题目大意 1.将x到当前根路径上的所有点染成一种新的颜色: 2.将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根: 3.查询以x为根的子树中所有点权值的平均值. 分析 原题codec ...

  7. bzoj 2819 Nim dfn序+树状数组维护区间异或值

    题目大意 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可以不取.谁不能取谁输.这个游戏是有必胜策略 ...

  8. 51nod 1576 Tree and permutation(树的重心+dfn序)

    乍一看我不会. 先不考虑加点. 先考虑没有那个除\(2\). 考虑每一条边的贡献,假设某一条边把这棵树分成大小为x,y的两个部分. 那么这条边最多可以被使用\(min(x,y)*2\)次(因为有进有出 ...

  9. BZOJ2819 Nim 【dfn序 + lca + 博弈论】

    题目 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可以不取.谁不能取谁输.这个游戏是有必胜策略的. ...

随机推荐

  1. 不建议在for循环中使用”+”进行字符串拼接

    https://mp.weixin.qq.com/s/qG6bdhndAip9s-_XM9oP3A 为什么阿里巴巴不建议在for循环中使用”+”进行字符串拼接 互联网后端架构 1周前    

  2. 如何交叉编译curl?

    1. 先准备一下openssl库 编译openssl库的方法在此 2. 获取curl源码 wget https://curl.haxx.se/download/curl-7.65.3.tar.gz 2 ...

  3. python使用redis实现协同控制的分布式锁

    python使用redis实现协同控制的分布式锁 上午的时候,有个腾讯的朋友问我,关于用zookeeper分布式锁的设计,他的需求其实很简单,就是节点之间的协同合作. 我以前用redis写过一个网络锁 ...

  4. mac安装 bcolz出现错误

    使用的是命令pip install bcolz c-blosc//snappy-stubs-:: fatal error: 'algorithm' file not found #include &l ...

  5. 浅谈-对modbus的理解

    浅谈-对modbus的理解 一.简介 Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准.1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP ...

  6. Python命令行参数解析模块getopt使用实例

    Python命令行参数解析模块getopt使用实例 这篇文章主要介绍了Python命令行参数解析模块getopt使用实例,本文讲解了使用语法格式.短选项参数实例.长选项参数实例等内容,需要的朋友可以参 ...

  7. Oracle SQL 脚本跟踪

    NC Oracle SQL 脚本跟踪 脚本: select * from v$sqlarea a and a.LAST_ACTIVE_TIME >= to_date( '2013-02-21 1 ...

  8. 【Leetcode_easy】783. Minimum Distance Between BST Nodes

    problem 783. Minimum Distance Between BST Nodes 参考 1. Leetcode_easy_783. Minimum Distance Between BS ...

  9. 在Electron运行的子页面无法访问window.opener解决方案

    我们的首页有一个window.open打开子页面后反向刷新父页面的功能,但是主页面如果开启了nodeIntegration=true,这个时候再设置nativeWindowOpen是不启作用的.再被w ...

  10. 使用expect实现自动交互,shell命令行自动输入,脚本自动化,变量引用,expect spawn执行带引号命令,expect 变量为空,不生效,不能匹配通配符*,函数,数组

    背景 有需求,在允许命令或者脚本跳出交互行,需要进行内容输入,但需要人手动输入,不是很方便,此时可以通过expect来实现自动互动交互. expect是一个自动交互功能的工具,可以满足代替我们实际工作 ...