题目描述

给定一棵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. LyaoutParameters作用

    当你想要动态生成布局的时候,那么就要用到这个参数了.因为那时候你在布局文件里面写的width和height都不起作用了. LinearLayout linearLayout = (LinearLayo ...

  2. laravel5.2总结--软删除

    当模型被软删除时,它们并不会真的从数据库中被移除.而是会在模型上设置一个 deleted_at 属性并将其添加到数据库.如果对应模型被软删除,则deleted_at字段的值为删除时间,否则该值为空. ...

  3. 使用WMI Filter 实现组策略的筛选!

    今天接到一个客户的一个问题,提到需要分系统版本分发相应的MSI程序.比如简体版接受简体版的分发程序,繁体版接受繁体版的分发程序!这个建立组策略的不同版本分发本身不会太难,我们只需要建立两个不同组策略分 ...

  4. Python框架之Django学习笔记(五)

    第一个Django网页小结 进来的请求转入/hello/. Django通过在ROOT_URLCONF配置来决定根URLconf. Django在URLconf中的所有URL模式中,查找第一个匹配/h ...

  5. Selenium中自动输入10位随机数字的方法

    有时候项目中需要输入快递号,对于已输入过的快递单号则不能再次输入,这种问题怎么解决呢,可以看下这个方法 public static final String ALLCHAR = "01234 ...

  6. 非常全面的vim配置文件

    1.mac下vim全局配置目录 /usr/share/vim/vimrc 一般不对此文件做修改,在用户目录下创建自定义配置,目录为: /Users/xxxxx cd ~ 2自定义vim配置 配置功能: ...

  7. spaCy 并行分词

    spaCy 并行分词 在使用spacy的时候,感觉比nltk慢了许多,一直在寻找并行化的方案,好在找到了,下面给出spaCy并行化的分词方法使用示例: import spacy nlp = spacy ...

  8. opendatasource问题

    EXEC sp_configure 'show advanced options', 1 GO RECONFIGURE GO EXEC sp_configure 'Ad Hoc Distributed ...

  9. 【转】Unity3D学习日记(二)使用UGUI制作虚拟摇杆控制摄像机

    http://blog.csdn.net/begonia__z/article/details/51178907 前天撸了一个简单的UGUI虚拟摇杆,今天我就利用前天做的虚拟摇杆做了一个简单的摄像机控 ...

  10. vue-cli 脚手架分析

    Vue-cli 一.安装vue-cli 安装vue-cli的前提是你已经安装了npm,安装npm你可以直接下载node的安装包进行安装.你可以在命令行工具里输入npm -v  检测你是否安装了npm和 ...