Description

有一棵树,要求支持

  1. 查询两点间简单路径的所有子链的异或和的和
  2. 修改某条边的权值

Solution

这种树上异或问题首先应该想到对于每个点存下一个前缀异或和表示这个点到根节点路径的异或和。那么两点之间路径的异或和就等于这两点的前缀和再异或起来。

于是操作一变成了:有k个点,每个点有权值,问\(\sum \limits_{i=1}^k\sum\limits_{j=i+1}^k val[i]\oplus val[j]\)

由于是异或运算,我们按位考虑。

对于二进制位 \(p\),假设这 \(k\) 个数中有 \(x\) 个的第 \(p\) 位为1,剩下的为 \(0\),那么对答案有贡献的实际上就只有 \(x\times (k-x)\) 个点对,也就是说只有这么多点对异或起来的值为 \(1\)。这启示我们对于每个二进制位,都找到多少位是0,多少位是1,把他们乘起来就好了。

Code

#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 30005
using std::min;
using std::max;
using std::swap;
#define int long long
#define ls cur<<1,l,mid,ql,qr
#define rs cur<<1|1,mid+1,r,ql,qr int head[N],dfn[N],top[N],d[N];
int n,m,cnt,tot,lazy[N<<2],cme[N];
int sze[N],son[N],dis[N],fs[N],fa[N]; struct Edge{
int to,nxt,dis;
}edge[N<<1]; struct Node{
int a[12][2]; friend Node operator+(Node x,Node y){
Node z;memset(z.a,0,sizeof z.a);
for(int i=1;i<=10;i++){
z.a[i][0]=x.a[i][0]+y.a[i][0];
z.a[i][1]=x.a[i][1]+y.a[i][1];
} return z;
}
}sum[N<<2]; void add(int x,int y,int z){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
edge[cnt].dis=z;
head[x]=cnt;
} inline int getint(){
int X=0;int w=0;char ch=0;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
} void dfs(int now){
sze[now]=1;
for(int i=head[now];i;i=edge[i].nxt){
int to=edge[i].to;
if(sze[to]) continue;
d[to]=d[now]+1;
dis[to]=dis[now]^edge[i].dis;cme[to]=edge[i].dis;
dfs(to);sze[now]+=sze[to];fa[to]=now;
if(sze[to]>sze[son[now]])
son[now]=to;
}
} void dfs2(int now,int low){
dfn[now]=++tot;fs[tot]=now;top[now]=low;
if(son[now])
dfs2(son[now],low);
for(int i=head[now];i;i=edge[i].nxt){
int to=edge[i].to;
if(dfn[to]) continue;
dfs2(to,to);
}
} void pushup(int cur){
sum[cur]=sum[cur<<1]+sum[cur<<1|1];
} void build(int cur,int l,int r){
if(l==r){
int now=dis[fs[l]];
for(int i=1;i<=10;i++){
if(now>>i-1&1)
sum[cur].a[i][1]++;
else sum[cur].a[i][0]++;
} return;
}
int mid=l+r>>1;
build(cur<<1,l,mid);build(cur<<1|1,mid+1,r);
pushup(cur);
} void pushdown(int cur){
if(!lazy[cur]) return;
for(int i=1;i<=10;i++){
if(lazy[cur]>>i-1&1){
swap(sum[cur<<1].a[i][0],sum[cur<<1].a[i][1]);
swap(sum[cur<<1|1].a[i][0],sum[cur<<1|1].a[i][1]);
}
}
lazy[cur<<1]^=lazy[cur];lazy[cur<<1|1]^=lazy[cur];lazy[cur]=0;
} Node query(int cur,int l,int r,int ql,int qr){
if(ql<=l and r<=qr)
return sum[cur];
int mid=l+r>>1;pushdown(cur);
Node z;memset(z.a,0,sizeof z.a);
if(ql<=mid)
z=z+query(ls);
if(mid<qr)
z=z+query(rs);
return z;
} int ask(int x,int y){
Node z;memset(z.a,0,sizeof z.a);
while(top[x]!=top[y]){
// printf("X=%lld,y=%lld\n",x,y);
if(d[top[x]]<d[top[y]])
swap(x,y);
z=z+query(1,1,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(d[x]<d[y]) swap(x,y);
z=z+query(1,1,n,dfn[y],dfn[x]);
int ans=0;
for(int i=1;i<=10;i++)
ans+=(1<<i-1)*z.a[i][0]*z.a[i][1];
return ans;
} void modify(int cur,int l,int r,int ql,int qr,int z){
if(ql<=l and r<=qr){
for(int i=1;i<=10;i++){
if(z>>i-1&1)
swap(sum[cur].a[i][0],sum[cur].a[i][1]);
}
lazy[cur]^=z;return;
}
pushdown(cur);int mid=l+r>>1;
if(ql<=mid)
modify(ls,z);
if(mid<qr)
modify(rs,z);
pushup(cur);
} signed main(){
n=getint(),m=getint();
for(int i=1;i<n;i++){
int x=getint(),y=getint(),z=getint();
add(x,y,z);add(y,x,z);
}
d[1]=1;dfs(1);dfs2(1,1);build(1,1,n);
while(m--){
if(getint()==1){
int x=getint(),y=getint();
printf("%lld\n",ask(x,y));
} else{
int x=getint(),y=getint(),z=getint();
if(d[x]<d[y]) swap(x,y);
modify(1,1,n,dfn[x],dfn[x]+sze[x]-1,cme[x]^z);
cme[x]=z;
}
} return 0;
}

[Luogu 3401] 洛谷树的更多相关文章

  1. [洛谷P3401] 洛谷树

    洛谷题目连接:洛谷树 题目背景 萌哒的Created equal小仓鼠种了一棵洛谷树! (题目背景是辣鸡小仓鼠乱写的QAQ). 题目描述 树是一个无环.联通的无向图,由n个点和n-1条边构成.树上两个 ...

  2. 洛谷树剖模板题 P3384 | 树链剖分

    原题链接 对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树 剩下的就和树剖一样了 #include< ...

  3. Luogu P1738 洛谷的文件夹

    P1738 Luogu 发一个链表题解! 仅有24ms,排名第一哦~ 圆圈代表点,每个店有两个指针,一个指向自己兄弟(同级文件夹),另一个指向自己孩子(子文件夹),还有一个保存当前名字. 有点像二叉树 ...

  4. 让lu哥头痛了许久的代码(洛谷:树的统计)

    错在单点修改时传的是a,应该是id[a](Line 89).谨记!!! //fushao zuishuai #include <cstdio> #include <cstring&g ...

  5. 洛谷P3655 差分数组 树状数组

    题目链接:https://www.luogu.org/problemnew/show/P3655 不一定对,仅供参考,不喜勿喷,不喜勿喷. 先copy洛谷P3368 [模板]树状数组 2 题解里面一位 ...

  6. 洛谷P4332 [SHOI2014]三叉神经树(LCT,树剖,二分查找,拓扑排序)

    洛谷题目传送门 你谷无题解于是来补一发 随便百度题解,发现了不少诸如树剖\(log^3\)LCT\(log^2\)的可怕描述...... 于是来想想怎么利用题目的性质,把复杂度降下来. 首先,每个点的 ...

  7. 洛谷P2922 [USACO008DEC] 秘密消息Secret Message [Trie树]

    洛谷传送门,BZOJ传送门 秘密消息Secret Message Description     贝茜正在领导奶牛们逃跑.为了联络,奶牛们互相发送秘密信息.     信息是二进制的,共有M(1≤M≤5 ...

  8. 【题解】洛谷P4145 花神游历各国(线段树)

    洛谷P4145:https://www.luogu.org/problemnew/show/P4145 思路 这道题的重点在于sqrt(1)=1 一个限制条件 与正常线段树不同的是区间修改为开方 那么 ...

  9. 【题解】洛谷P1198 [JSOI2008] 最大数(线段树)

    洛谷P1198:https://www.luogu.org/problemnew/show/P1198 思路 一道水水的线段树 20分钟A掉 这道题只涉及到单点修改和区间查询 所以这道题甚至不用Laz ...

随机推荐

  1. ibatis (六) dynamic的用法

    view plain copy print? dynamic可以去除第一个prepend="and"中的字符(这里为and),从而可以帮助你实现一些很实用的功能.具体情况如下: 1 ...

  2. Java集合:LinkedList源码解析

    Java集合---LinkedList源码解析   一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据re ...

  3. C#中 property 与 attribute的区别

    说的通俗些Attribute是类,不过是一类比较特殊的类,Attribute必须写在一对方括号中,用来处理.NET中多种问题:序列化.程序的安全特征等等,在.NET中的作用非同凡响 Attribute ...

  4. java web+模板

    这次测试需要在java web的基础上套入模板,在测试的过程中我遇到了许多问题,现在我可以使用模板来美化网页的许多格式.但是模板的许多代码我还是看不懂,其中有jquery的许多代码.在今后我会学习相关 ...

  5. 在cmd下可以import cv2,而Pycharm报错:找不到cv2

    平台:win10 x64+Pycharm+Anaconda3+opencv 安装教程:参考博客——http://blog.sina.com.cn/s/blog_cca23c300102xiy4.htm ...

  6. delphi 中OutputDebugString 函数的妙用(转载)

    原文地址 https://www.peganza.com/delphi-and-outputdebugstring.html Ever wanted to monitor your Delphi ap ...

  7. 2019.03.04 bzoj5308: [Zjoi2018]胖(二分答案+st表)

    传送门 想题5分钟调题两小时系列 其实还是我tcl 读完题之后自然会知道一个关键点能够更新的点是一段连续的区间,于是我们对于每个点能到的左右区间二分答案,用ststst表维护一下查询即可. 代码: # ...

  8. mac开发常用工具和插件记录

    1.alfred 是 Mac 系统上一款专注于效率提升的著名应用,它能帮你快速打开网页.快速进行自定义搜索.查看剪贴板历史.快速查询单词等等.Alfred 提供的功能虽然很多,但目的只有一个 —— 那 ...

  9. SQL STUFF函数 拼接字符串 多列 合并成一列 转

    关于和并列的 要这种效果. create table tb(idint, value varchar(10)) insert into tbvalues(1,'aa') insert into tbv ...

  10. Python简介及环境安装

    Python 官网传送门 Python是一种面向对象的解释性计算机程序设计语言. Python 2.7将于2020年1月1日终止支持,本笔记基于Python3. pip pip 是一个现代的,通用的 ...