正题


题目大意

给出两棵树,对于第一棵树的每一条边(x,y)(x,y)(x,y)询问有多少条在第二棵树上的边(u,v)(u,v)(u,v)与其交换(连接的序号相同)后两棵树依旧是一棵树。

1≤n≤2×1051\leq n\leq 2\times 10^51≤n≤2×105


解题思路

先只考虑一棵树的合法情况,对于第二棵树的边(u,v)(u,v)(u,v)交换过来合法的当且仅当(x,y)(x,y)(x,y)在u→vu\rightarrow vu→v路径上,同理的对于第二棵树合法当且仅当(u,v)(u,v)(u,v)在x→yx\rightarrow yx→y路径上。

那么考虑限制一个条件,第二个条件用数据结构查询。

我们把所有的(u,v)(u,v)(u,v)用树上差分挂在第一棵树的u→vu\rightarrow vu→v路径上,然后遇到一条(u,v)(u,v)(u,v)我们让这棵树的这条边权值+1+1+1。

这样我们就保证了处理到边(x,y)(x,y)(x,y)时有权值的只有在第一棵树上经过(x,y)(x,y)(x,y)的u→vu\rightarrow vu→v,那么至于第二个要求我们直接在第二棵树上查询x→yx\rightarrow yx→y路径上的权值和。这个可以用树链剖分维护。

而树上差分的合并功能就用线段树合并就好了。

时间复杂度:O(nlog⁡2n)O(n\log^2n)O(nlog2n)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=2e5+10,U=20;
int n,cnt,depG[N],f[N][U],rt[N],ans[N];
int siz[N],fa[N],dep[N],son[N],top[N],id[N];
vector<pair<int,int> > G[N];
vector<int> T[N],v[N];
pair<int,int> e[N];
struct SegTree{int w[N<<5],ls[N<<5],rs[N<<5];void Change(int &x,int L,int R,int pos,int val){if(!x)x=++cnt;w[x]+=val;if(L==R)return;int mid=(L+R)>>1;if(pos<=mid)Change(ls[x],L,mid,pos,val);else Change(rs[x],mid+1,R,pos,val);}int Ask(int x,int L,int R,int l,int r){if(!x)return 0;if(L==l&&R==r)return w[x];int mid=(L+R)>>1;if(r<=mid)return Ask(ls[x],L,mid,l,r);if(l>mid)return Ask(rs[x],mid+1,R,l,r);return Ask(ls[x],L,mid,l,mid)+Ask(rs[x],mid+1,R,mid+1,r);}int Merge(int x,int y,int L,int R){if(!x||!y)return x|y;w[x]+=w[y];if(L==R)return x;int mid=(L+R)>>1;ls[x]=Merge(ls[x],ls[y],L,mid);rs[x]=Merge(rs[x],rs[y],mid+1,R);return x;}
}S;
void preset(int x,int fa){f[x][0]=fa;depG[x]=depG[fa]+1;for(int i=0;i<G[x].size();i++){int y=G[x][i].first;if(y==fa)continue;preset(y,x);}return;
}
int LCA(int x,int y){if(depG[x]<depG[y])swap(x,y);for(int i=U-1;i>=0;i--)if(depG[f[x][i]]>=depG[y])x=f[x][i];if(x==y)return x;for(int i=U-1;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];return f[x][0];
}
void dfs1(int x){dep[x]=dep[fa[x]]+1;siz[x]=1;for(int i=0;i<T[x].size();i++){int y=T[x][i];if(y==fa[x])continue;fa[y]=x;dfs1(y);siz[x]+=siz[y];if(siz[y]>siz[son[x]])son[x]=y;}return;
}
void dfs2(int x){id[x]=++cnt;if(son[x]){top[son[x]]=top[x];dfs2(son[x]);}for(int i=0;i<T[x].size();i++){int y=T[x][i];if(y==fa[x]||y==son[x])continue;top[y]=y;dfs2(y);}return;
}
int GetAns(int x,int y,int rt){int ans=0;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);ans+=S.Ask(rt,1,n,id[top[x]],id[x]);x=fa[top[x]];}if(dep[x]>dep[y])swap(x,y);if(x!=y)ans+=S.Ask(rt,1,n,id[x]+1,id[y]);return ans;
}
void solve(int x,int fa,int ids){for(int i=0;i<G[x].size();i++){int y=G[x][i].first,id=G[x][i].second;if(y==fa)continue;solve(y,x,id);rt[x]=S.Merge(rt[x],rt[y],1,n);}if(ids){for(int i=0;i<v[x].size();i++){int p=abs(v[x][i]);int X=e[p].first,Y=e[p].second;if(dep[X]>dep[Y])swap(X,Y);S.Change(rt[x],1,n,id[Y],(v[x][i]>0)?1:-2);}ans[ids]=GetAns(fa,x,rt[x]);}return;
}
int main()
{freopen("exchange.in","r",stdin);freopen("exchange.out","w",stdout);scanf("%d",&n);for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);G[x].push_back(mp(y,i));G[y].push_back(mp(x,i));}for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);T[x].push_back(y);T[y].push_back(x);e[i]=mp(x,y);}preset(1,0);for(int j=1;j<U;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];for(int i=1;i<n;i++){int x=e[i].first,y=e[i].second,lca=LCA(x,y);v[x].push_back(i);v[y].push_back(i);v[lca].push_back(-i);}dfs1(1);top[1]=1;dfs2(1);solve(1,0,0);for(int i=1;i<n;i++)printf("%d ",ans[i]);return 0;
}

YbtOJ-交换游戏【树链剖分,线段树合并】相关推荐

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  2. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  3. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  4. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  5. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

  6. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  7. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  8. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  9. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  10. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

最新文章

  1. csu 1976: 搬运工小明
  2. vuex模块化 怎么引用state_[Vuex系列] - 细说state的几种用法
  3. suse linux 安装oracle,SUSE Linux下安装Oracle 11g服务器
  4. vue-cli 将被 create-vue 替代?初始化基于 vite 的 vue3 项目为何如此简单?
  5. 机器学习的一些注意事项
  6. java实现可有括号的android计算器
  7. 搭建: canal部署与实例运行
  8. HDU2027 统计元音【入门】
  9. vnc远程软件,盘点六款你值得拥有的vnc远程软件
  10. Linux内核4.1在file_operations的read_iter和write_iter
  11. 细化(thinning)
  12. 互联网金融系列-支付清算体系介绍-下篇
  13. 主板芯片组和内存映射
  14. 薇娅,李佳琦都点赞的淘宝双11直播系统,是如何打造的?
  15. 实现所有网站的qq登录返回登录后的cookie信息
  16. python做游戏辅助用到的库
  17. 八皇后问题动态演示_Qt5实现
  18. 【node】windows使用 npm i -g报错operation not permitted解决方法
  19. coffee-script运行环境
  20. Windows1.0到Windows10三十年进化史,你还记得自己最初使用的系统吗?

热门文章

  1. 计算机视觉招聘_INDEMIND|SLAM、计算机视觉、深度学习算法招聘(社招实习)
  2. 51单片机外部地址c语言,cx51与c语言对单片机内部和外部资源变量和地址的定义是否兼容?为什么...
  3. mysql 查询空字符串 设置默认值_MySQL默认值选型是空,还是 NULL-爱可生
  4. 网页表格线框html,关于Dreamweaver中怎么让html网页中的table边框细线显示?
  5. 传递集合对象_面试必备——Java集合框架
  6. 单调谐回路谐振放大器等效电路分析_手把手教你如何分析三极管电路
  7. 多个cpp文件生成so_boostpython:从多个.cpp文件创建一个模块(.so)
  8. linux脚本传参修改配置文件,shell脚本修改配置文件指定行的值
  9. 软件构造学习笔记-第六周
  10. leetcode209. 长度最小的子数组(暴力+滑动窗口)