bzoj 4530(DFS序+线段树合并)
来源:互联网 发布:mac 双定制粉底液 肤质 编辑:程序博客网 时间:2024/06/02 02:04
传送门
题解:对每个点建权值线段树(权值即点在DFS序列中的编号),合并的时候直接合并两个点根的线段树,并连一下并查集,查询的时候找到x,y所在树的根f,假设dep[x]>dep[y],那答案就是(size[f]-size[x])*size[x](这一点的解释尽快补上,不过好像不比较也能过,难道是数据水?)。
P.S.在询问时要选深度更深的点的原因:
如果dep[x] < dep[y]并且选择了x,那么x的子树就包括了y点,而答案是两边子树大小的乘积,所以这样会造成多余贡献,不合法。
#include<bits/stdc++.h>using namespace std;const int MAXN=1e5+4;int n,m;int head[MAXN],fa[MAXN],edge=0;int dep[MAXN],in[MAXN],out[MAXN],tim=0;bool vis[MAXN];struct EDGE { int v,nxt;}e[MAXN<<1];struct Q { int opt,x,y;}q[MAXN];int siz[MAXN*18],lc[MAXN*18],rc[MAXN*18],root[MAXN],tot=0;int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]);}inline void adde(int u,int v) { e[++edge].nxt=head[u],e[edge].v=v,head[u]=edge; e[++edge].nxt=head[v],e[edge].v=u,head[v]=edge;}inline int read() { int x=0;char c=getchar(); while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x;}inline void pushup(int rt) { siz[rt]=siz[lc[rt]]+siz[rc[rt]];}void insert(int &rt,int l,int r,int val) { rt=++tot; if (l==r) {siz[rt]=1;return ;} int mid=(l+r)>>1; if (val<=mid) insert(lc[rt],l,mid,val); else insert(rc[rt],mid+1,r,val); pushup(rt);}inline int merge(int a,int b) { if (!a) return b; if (!b) return a; lc[a]=merge(lc[a],lc[b]); rc[a]=merge(rc[a],rc[b]); pushup(a); return a;}int query(int rt,int l,int r,int L,int R) { if (L<=l&&r<=R) return siz[rt]; int mid=(l+r)>>1,ret=0; if (L<=mid) ret+=query(lc[rt],l,mid,L,R); if (mid<R) ret+=query(rc[rt],mid+1,r,L,R); return ret;}void dfs(int p,int fa) { in[p]=++tim,vis[p]=true; insert(root[p],1,n,in[p]); for (int i=head[p];~i;i=e[i].nxt) { int v=e[i].v; if (v^fa) dep[v]=dep[p]+1,dfs(v,p); } out[p]=tim;}int main() {// freopen("bzoj 4530.in","r",stdin); memset(head,-1,sizeof(head)); memset(vis,false,sizeof(vis)); n=read(),m=read(); for (register int i=1;i<=m;++i) { char ss; while (!isalpha(ss=getchar())); q[i].opt=(ss^'Q')?1:2; q[i].x=read(),q[i].y=read(); if (q[i].opt&1) adde(q[i].x,q[i].y); } for (register int i=1;i<=n;++i){ fa[i]=i; if (!vis[i]) dep[i]=0,dfs(i,0); }/* for (int i=1;i<=n;++i) cout<<dep[i]<<' '; cout<<endl;*/ for (register int i=1;i<=m;++i) { if (q[i].opt&1) { int x=q[i].x,y=q[i].y; x=find(x),y=find(y); if (dep[x]>dep[y]) x^=y^=x^=y;//find the earlier-linked node(new node link to old node) root[x]=merge(root[x],root[y]); fa[y]=x; } else { int x=q[i].x,y=q[i].y; int pos=(dep[x]<dep[y])?y:x;//find the later-linked node to avoid repeated calculation int f=find(pos); int temp=query(root[f],1,n,in[pos],out[pos]); printf("%lld\n",1ll*(siz[root[f]]-temp)*temp); } } return 0;}
阅读全文
0 0
- bzoj 4530(DFS序+线段树合并)
- BZOJ 4756 Promotion Counting(线段树合并 || dfs)
- bzoj 4551(DFS序+线段树)
- bzoj 3306: 树 dfs序+线段树
- bzoj 3252: 攻略 (线段树+DFS序)
- BZOJ 1103 DFS序+线段树
- BZOJ 4034 线段树+DFS序
- BZOJ 2819 DFS序+线段树
- BZOJ 3252攻略 dfs序+线段树
- DFS序+线段树(bzoj 4034)
- bzoj 4756(线段树合并)
- bzoj 2212(线段树合并)
- BZOJ 3123 线段树合并
- 【BZOJ 3306】树【LCA、DFS序、线段树】
- BZOJ 4551 树 dfs序+线段树 / 并查集
- 【BZOJ】【P3252】【攻略】【题解】【贪心+dfs序+线段树】
- BZOJ 4034 HAOI2015 T2 DFS序+线段树
- BZOJ 3779 重组病毒 LCT+线段树维护DFS序
- 去除数据库数据表中重复的记录的sql语句
- 关于CSS的一些基础内容
- markdown 的简单使用
- 对朱刘算法求最小树形图的理解(uva11865)
- JZOJ 5267. 费马点问题
- bzoj 4530(DFS序+线段树合并)
- 9.28-9.29 课程记录
- 小薇学院任务一:零基础HTML编码(笔记)
- bzoj 1966: [Ahoi2005]VIRUS 病毒检测
- Python学习笔记:高阶函数(函数指针)与装饰器
- MySQL之DML语句(上)
- 梯度下降法的三种形式BGD、SGD以及MBGD
- BZOJ 2115 Xor 线性基介绍(高斯消元 xor线性基)
- AJAX提交到Handler.ashx一般处理程序返回json数据 (字符串拼接方式)