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. ubuntu 应用添加进环境变量

    BG:公司同事使用的电脑系统大多为windows ,有部分mac和Ubuntu(我就是那个部分Ubuntu),某些情况为了统一格式,便下载了一些解压即可使用的软件,但是每次点开文件夹然后点开程序很繁琐 ...

  2. ABP框架系列之一:(Entity-实体)

    Entities are one of the core concepts of DDD (Domain Driven Design). Eric Evans describe it as " ...

  3. save to project-level dictionary? save to application-level dictionary?

    通过静态代码分析工具lint在Spelling typo得到save to project-level dictionary? save to application-level dictionary ...

  4. 从中央仓库下载所想要的jar包

    中央仓库地址:https://mvnrepository.com/ 这边我搜索一个commons-logging包作为例子: 点击下面第二个绿色的comons-logging进入这个页面: 一.win ...

  5. 通过selenium登录网页获取特定信息

    前言 最近有需求要登录网站查询一些信息,然后再修改一些信息,而且这种工作重复性很强,想着通过自动化的方式来做这个东西. 技术选择 自动化的方式开始考虑的是用python的爬虫来做,但是登录的网站有好多 ...

  6. Visual Studio 2013 配置多个Release版本,并为每个版本配置预编译的宏

    最近开发过程中,需要将同一份工程编译成两个版本,分别为ReleaseA和ReleaseB. ReleaseB比ReleaseA少了部分功能,所以希望在编译的时候,根据不同的版本编译工程中相应的代码. ...

  7. 「NOI2018」屠龙勇士(EXCRT)

    「NOI2018」屠龙勇士(EXCRT) 终于把传说中 \(NOI2018D2\) 的签到题写掉了... 开始我还没读懂题目...而且这题细节巨麻烦...(可能对我而言) 首先我们要转换一下,每次的 ...

  8. ElasticSearch权威指南学习(索引管理)

    创建索引 当我们需要确保索引被创建在适当数量的分片上,在索引数据之前设置好分析器和类型映射. 手动创建索引,在请求中加入所有设置和类型映射,如下所示: PUT /my_index { "se ...

  9. pdf.js显示合同签名问题

    需求 pdf页面显示在ios11以下的环境,合同的签名印章或签字会显示不出 解决方案(初步处理参考下文引用,这里是后续具体做法) 现在通过使用pdf.js插件,参考下文,引入自己的代码 我把gener ...

  10. css 设计规范

    外部 div 设置 margin 和 padding: 内部每个元素只设计跟自己相关的属性,这样方便复用: