题目描述

给定一棵n 个点的树,每条边上都有一个权值。现在按顺序删掉所有的n-1条边,每删掉一条边询问当前有多少条路径满足路径上所有边权值异或和为0。

输入输出格式

输入格式:

第一行一个整数n。

接下来n-1 行,每行三个整数ai,bi, zi,满足1<= ai, bi <=n,表示树上编号为ai 的点和编号为bi 的点中间连有一条权值为zi 的边。

接下来一行n-1 个整数,两两之间有一个空格隔开,表示一个1~ n- 1 的排列,表示n - 1 条边的删边顺序。

输出格式:

输出n 行,每行一个整数,依次表示删掉第0~ n - 1 条边之后的边权异或和为零的路径数。

输入输出样例

输入样例#1:

4
1 2 0
2 3 0
2 4 0
3 1 2
输出样例#1:

6
3
1
0

说明

对于20% 数据,满足n <= 1000。

对于另外30% 数据,满足所有的zi = 0。

对于全部数据,满足n <=10^5,0<= zi<= 10^9。

洛谷上多一些像这样质量高的原创题就好啦qwq(吐槽一下)

首先不考虑删边什么乱七八糟的,假如就是给你一棵树,问你多少对点之间的路径Xor和为零,该怎么求???

"我知道我知道,那不就是点分一下,经过当前重心的可以O(子树大小)求出(两个端点到根的路径Xor和相同就算一对),不经过的可以递归下去找,每一层还不用排序,总共O(N log N)就ojbk啦!"

"抱歉,其实dfs一遍就好了。。。。。"

由于Xor极其特殊的性质(Xor一个数两边相当于啥也没做),所以我们可以直接随便选个根然后一遍dfs统计Xor[](到根的路径异或和)一样的点对数就好啦,因为LCA以上的路径被异或了两次相当于没有异或。。。

有了这个较为简单的算法我们就很好去搞动态的情况了。

众所周知,加边比删边来的简单,于是我们可以反着做,考虑加入一条边会新产生多少点对路径Xor和为0.

当然,到了这还需要一点脑洞:我们用并查集去维护当前每个点所在的树根是哪个,并在树根上挂一个 unordered_map,记录一下这颗小树的所有点的Xor[] (当然只需要记 对于任意x , Xor[i] = x 的 i 有多少个就好啦)。合并的时候,因为两个联通分量的树根不一样,所以要暴力把小的树的Xor[]重新算一下(以大树树根为基准),并清空小树的unordered_map,然后把新算的Xor[]加入到大树树根的unordered_map中,最后就是并查集的合并了,别忘了在图中还要加边。。。不然以后没法dfs了233.

但是看起来好暴力啊?会不会超时啊???

但这是启发式合并啊,一颗大小为siz的树会对合并的时间复杂度贡献一个 siz 当且仅当它和一个 大小 >siz 的树合并了,得到一个大小 >2*siz 的新树,所以一个点最多贡献log N次合并的复杂度就到大树里啦,所以总的复杂度就是O(N log N)啦。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define pb push_back
const int maxn=100005;
unordered_map<int,int> mmp[maxn];
int n,m,Fa[maxn],p[maxn],u[maxn],v[maxn],w[maxn],S[maxn],T,tp;
int to[maxn*2],ne[maxn*2],hd[maxn],num,siz[maxn],Xor[maxn],val[maxn*2];
inline void add(int x,int y,int z){ to[++num]=y,ne[num]=hd[x],hd[x]=num,val[num]=z;}
int getFa(int x){ return Fa[x]==x?x:(Fa[x]=getFa(Fa[x]));}
ll ans[maxn],now; void dfs(int x,int fa){
S[++tp]=Xor[x],now+=(ll)mmp[T][Xor[x]];
for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa) Xor[to[i]]=Xor[x]^val[i],dfs(to[i],x);
} inline void Merge(int x,int y,int z){
int fa=getFa(x),fb=getFa(y);
if(siz[fa]>siz[fb]) swap(fa,fb),swap(x,y); mmp[fa].clear(),Fa[fa]=fb,siz[fb]+=siz[fa];
Xor[x]=Xor[y]^z,T=fb,dfs(x,y); for(;tp;tp--) mmp[T][S[tp]]++;
add(x,y,z),add(y,x,z);
} inline void solve(){
for(int i=n-1;i;i--){
Merge(u[p[i]],v[p[i]],w[p[i]]);
ans[n-i]=now;
}
} int main(){
scanf("%d",&n);
for(int i=1;i<n;i++) scanf("%d%d%d",u+i,v+i,w+i);
for(int i=1;i<n;i++) scanf("%d",p+i);
for(int i=1;i<=n;i++) siz[i]=1,Fa[i]=i,mmp[i][0]=1,Xor[i]=0; solve(); for(int i=n-1;i>=0;i--) printf("%lld\n",ans[i]);
return 0;
}

  

洛谷 P3359 改造异或树的更多相关文章

  1. 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  2. [luogu3359]改造异或树

    [luogu3359]改造异或树 luogu 和之前某道题类似只有删边的话考虑倒着加边 但是怎么统计答案呢? 我们考虑以任意点为根dfs一遍求出每个点到根的路径异或和s[i] 这样任意两点x,y的路径 ...

  3. 洛谷p3384【模板】树链剖分题解

    洛谷p3384 [模板]树链剖分错误记录 首先感谢\(lfd\)在课上调了出来\(Orz\) \(1\).以后少写全局变量 \(2\).线段树递归的时候最好把左右区间一起传 \(3\).写\(dfs\ ...

  4. 洛谷P3688/uoj#291. [ZJOI2017]树状数组

    传送门(uoj) 传送门(洛谷) 这里是题解以及我的卡常数历程 话说后面那几组数据莫不是lxl出的这么毒 首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间 ...

  5. 洛谷 P3384 【模板】树链剖分

    树链剖分 将一棵树的每个节点到它所有子节点中子树和(所包含的点的个数)最大的那个子节点的这条边标记为"重边". 将其他的边标记为"轻边". 若果一个非根节点的子 ...

  6. 洛谷P3459 [POI2007]MEG-Megalopolis(树链剖分,Splay)

    洛谷题目传送门 正解是树状数组维护dfn序上的前缀和,这样的思路真是又玄学又令我惊叹( 我太弱啦,根本想不到)Orz各路Dalao 今天考了这道题,数据范围还比洛谷的小,只有\(10^5\)(害我复制 ...

  7. [洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?

    其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客 Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数 ...

  8. 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

    推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...

  9. 洛谷P2617 Dynamic Rankings (主席树)

    洛谷P2617 Dynamic Rankings 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a ...

随机推荐

  1. Django templates(模板)

    为什么用templates? views.py视图函数是用来写Python代码的,HTML可以被直接硬编码在views.py之中.如下: import datetime def current_tim ...

  2. leetcode 【 Linked List Cycle II 】 python 实现

    公司和学校事情比较多,隔了好几天没刷题,今天继续刷起来. 题目: Given a linked list, return the node where the cycle begins. If the ...

  3. 【Remove Duplicates from Sorted Array】cpp

    题目: https://leetcode.com/problems/remove-duplicates-from-sorted-array/ Given a sorted array, remove ...

  4. 【Luogu P1661】扩散

    题目: 一个点每过一个单位时间就会向四个方向扩散一个距离,如图. 两个点$a$.$b$连通,记作$e(a,b)$,当且仅当$a$.$b$的扩散区域有公共部分.连通块的定义是块内的任意两个点$u$.$v ...

  5. 程序集链接器(AL.exe)

    AL.exe使用程序可以生成一个EXE文件或者DLL PE文件(其中只包含对其他模块中的类型进行描述的一个清单). 不要在普通的命令行窗口中编译,请先打开C:\ProgramData\Microsof ...

  6. Python+Selenium练习篇之3-利用tag name定位元素

    前一篇文章介绍了如何通过元素的id值来定位web元素,本文介绍如何通过tag name来定位元素.个人认为,通过tag name来定位还是有很大缺陷,定位不够精确.主要是tag name有很多重复的, ...

  7. Leetcode 516.最长回文子序列

    最长回文子序列 给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 示例 1:输入: "bbbab" 输出: 4 一个可能的最长回文子序列为 " ...

  8. 实用拜占庭容错算法PBFT

    实用拜占庭容错算法PBFT 实用拜占庭容错算法PBFT 96 乔延宏 2017.06.19 22:58* 字数 1699 阅读 4972评论 0喜欢 11 分布式架构遭遇的问题 分布式架构会遭遇到以下 ...

  9. c# 操作access数据库image ole字段

    using System; using System.Data; using System.Configuration; using System.Web; using System.Data.Ole ...

  10. 【Luogu】P2485计算器(快速幂,exgcd和Bsgs模板)

    题目链接 题目描述非常直接,要求你用快速幂解决第一问,exgcd解决第二问,bsgs解决第三问. emmmm于是现学bsgs 第二问让求最小整数解好烦啊…… 假设我们要求得方程$ax+by=c(mod ...