[Luogu 3401] 洛谷树
Description
有一棵树,要求支持
- 查询两点间简单路径的所有子链的异或和的和
- 修改某条边的权值
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] 洛谷树的更多相关文章
- [洛谷P3401] 洛谷树
洛谷题目连接:洛谷树 题目背景 萌哒的Created equal小仓鼠种了一棵洛谷树! (题目背景是辣鸡小仓鼠乱写的QAQ). 题目描述 树是一个无环.联通的无向图,由n个点和n-1条边构成.树上两个 ...
- 洛谷树剖模板题 P3384 | 树链剖分
原题链接 对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树 剩下的就和树剖一样了 #include< ...
- Luogu P1738 洛谷的文件夹
P1738 Luogu 发一个链表题解! 仅有24ms,排名第一哦~ 圆圈代表点,每个店有两个指针,一个指向自己兄弟(同级文件夹),另一个指向自己孩子(子文件夹),还有一个保存当前名字. 有点像二叉树 ...
- 让lu哥头痛了许久的代码(洛谷:树的统计)
错在单点修改时传的是a,应该是id[a](Line 89).谨记!!! //fushao zuishuai #include <cstdio> #include <cstring&g ...
- 洛谷P3655 差分数组 树状数组
题目链接:https://www.luogu.org/problemnew/show/P3655 不一定对,仅供参考,不喜勿喷,不喜勿喷. 先copy洛谷P3368 [模板]树状数组 2 题解里面一位 ...
- 洛谷P4332 [SHOI2014]三叉神经树(LCT,树剖,二分查找,拓扑排序)
洛谷题目传送门 你谷无题解于是来补一发 随便百度题解,发现了不少诸如树剖\(log^3\)LCT\(log^2\)的可怕描述...... 于是来想想怎么利用题目的性质,把复杂度降下来. 首先,每个点的 ...
- 洛谷P2922 [USACO008DEC] 秘密消息Secret Message [Trie树]
洛谷传送门,BZOJ传送门 秘密消息Secret Message Description 贝茜正在领导奶牛们逃跑.为了联络,奶牛们互相发送秘密信息. 信息是二进制的,共有M(1≤M≤5 ...
- 【题解】洛谷P4145 花神游历各国(线段树)
洛谷P4145:https://www.luogu.org/problemnew/show/P4145 思路 这道题的重点在于sqrt(1)=1 一个限制条件 与正常线段树不同的是区间修改为开方 那么 ...
- 【题解】洛谷P1198 [JSOI2008] 最大数(线段树)
洛谷P1198:https://www.luogu.org/problemnew/show/P1198 思路 一道水水的线段树 20分钟A掉 这道题只涉及到单点修改和区间查询 所以这道题甚至不用Laz ...
随机推荐
- 《C#从现象到本质》读书笔记(七)第9章 泛型
<C#从现象到本质>读书笔记(七)第9章 泛型 泛型的三大好处:类型安全,增强性能(避免装箱和拆箱),代码复用. 泛型方法是传入的参数至少有一个类型为T(尚未制定的类型,根据微软的命名规则 ...
- nginx:location指令中的正则表达式
nginx:location指令中的正则表达式 uri匹配步骤 官网说明https://docs.nginx.com/nginx/admin-guide/web-server/web-server/ ...
- 消息模式Toast.makeText的几种常见用法
Toast 是一个 View 视图,快速的为用户显示少量的信息. Toast 在应用程序上浮动显示信息给用户,它永远不会获得焦点,不影响用户的输入等操作,主要用于 一些帮助 / 提示. Toast 最 ...
- turtle库的学习笔记
(1)turtle使用pen来绘制图形 pendown() 放下画笔,移动到指定点后继续绘制 penup() 提起画笔,用于另起一个地方绘制时使用 pensize(width) 设置画笔线条 ...
- easyui中的option设置selected没有效果
在mvc中,使用了easyUI框架,然后我点击添加新消息的时候弹窗一个新窗口,添加信息.却发现我的select一直无法设置默认状态,jq选中,还是直接在添加一条请选择的option都没办法选中,网络上 ...
- 【转】Closeable, Readable, Flushable, Appendable
Closeable: package java.io; import java.io.IOException; public interface Closeable { /** * Closes th ...
- Solutions and Summay for Linked List Naive and Easy Questions
1.Remove Linked List Elements package linkedlist; /* * Question: Remove all elements from a linked l ...
- Centos6.5安装中文支持和中文输入法
先来讲中文支持: 之前在网上查了不少资料,很多网友在网上都说,在shell命令下输入: # vi /etc/sysconfig/i18n 然后修改LANG="en_US.UTF-8& ...
- 项目Alpha冲刺(团队5/10)
项目Alpha冲刺(团队5/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...
- Spring Data Solr的分组查询 for 搜索面板的商品分类
private List searchCategoryList(Map searchMap) { SimpleQuery query = new SimpleQuery(new Criteria(&q ...