洛谷题目连接:洛谷树

题目背景

萌哒的Created equal小仓鼠种了一棵洛谷树!

(题目背景是辣鸡小仓鼠乱写的QAQ)。

题目描述

树是一个无环、联通的无向图,由n个点和n-1条边构成。树上两个点之间的路径被定义为他们之间的唯一一条简单路径——显然这是一条最短路径。

现在引入一个概念——子路径。假设树上两个点p1和pn之间的路径是P=<p1,p2,p3,…,pn>,那么它的子路径被定义为某一条路径P’,满足P’=<pi,pi+1,pi+2,…,pj>,其中1<=i<=j<=n。显然,原路径是一条子路径,任意一个点也可以作为子路径。

我们给每条边赋予一个边权。萌萌哒的Sugar问小仓鼠:对于任意两个点u和v,你能快速求出,u到v的路径上所有子路径经过的边的边权的xor值的和是多少。具体地说就是,你把u到v的路径上所有子路径全部提出来,然后分别把每个子路径上经过的边的边权xor在一起,最后求出得到的所有xor值的和。

什么?你不知道xor?那就去百度啊!

这时候,fjzzq2002大爷冒了粗来:窝还要你滋磁修改某条边边权的操作!

小仓鼠那么辣鸡,当然不会做这道题啦。于是他就来向你求救!

输入输出格式

输入格式:

第一行两个正整数n和q,表示点的个数,查询和询问的总次数。

接下来n-1行,每行两个正整数u、v、w,表示u和v两个点之间有一条边权为w的边。

接下来q行,格式为1 u v或2 u v w。如果为1 u v操作,你需要输出u到v的路径上所有子路径经过的边的边权的xor值的和是多少;如果为2 u v w操作,你需要把u到v这条边的边权改为w,保证这条边存在。

输出格式:

对于每个1操作,输出答案。

输入输出样例

输入样例#1:

5 3

1 2 3

2 3 3

2 4 6

4 5 1

1 3 4

2 2 4 7

1 3 5

输出样例#1:

14

26

说明

本题时限1s,内存限制128M,因新评测机速度较为接近NOIP评测机速度,请注意常数问题带来的影响。

【数据范围】

No    n=    q=    备注
1 100 5 无
2 100 20 无
3 100 100 无
4 5000 1000 无
5 5000 2000 无
6 5000 3000 无
7 10000 10000 第i条边连接第i个点和第i+1个点,且没有2操作
8 10000 20000 第i条边连接第i个点和第i+1个点,且没有2操作
9 10000 10000 第i条边连接第i个点和第i+1个点
10 10000 20000 第i条边连接第i个点和第i+1个点
11 10000 10000 没有2操作
12 10000 20000 没有2操作
13 20000 20000 没有2操作
14 30000 30000 没有2操作
15 30000 10000 无
16 20000 20000 无
17 20000 20000 无
18 30000 20000 无
19 20000 30000 无
20 30000 30000 无

对于100%的数据,所有边权小于等于1023。


一句话题意: 给出一棵树,要求出一条路径上的所有子段的异或值的和.并且要求支持修改操作.


题解: 要求一条路径上的子段的异或值的和,如果直接用朴素算法的话,需要枚举这个子段的两个端点.那么这样复杂度就是\(O(n^2)\)的了.

我们先来考虑这样一种情况:假设边的权值只有0和1.

因为题目要求的是把所有子段的异或和加起来,所以先将每个点到根的异或和统计起来,用树剖维护到线段树中.因为0与0异或后仍然是0,1与1异或也是,而这样都不能对答案做出贡献,所以就不用考虑加入答案.只有一个0和一个1异或后的值为1,也就是说答案就是0与1可以形成的组合的数量,也就是从根节点开始的异或和为0的个数乘以1的个数.

那么对于那些权值不是0和1的也可以转化成二进制的形式,然后再按位处理,也就是说,对于一条路径的查询可以分成11次查询的和(1023\(\leq2^{10}\)),分别查询第0~第10位的答案之和.

然后对于修改操作,因为我们在线段树中维护的是异或和,所以需要将修改的那条边的子树中的值都要修改(对于二进制每一位的修改),因为只有0和1,所以直接将区间的信息翻转一下就可以了.

可能讲的有点不清楚,可以通过样例模拟一下,然后看下代码理解一下吧.

#include<bits/stdc++.h>
#define ll(x) (x<<1)
#define rr(x) (x<<1|1)
using namespace std;
typedef int _int;
#define int long long
const int N=30000+5; int n, m, ecnt = 0, last[N], val[N], pre[N];
int size[N], son[N], fa[N], top[N], id[N], idx = 0, dep[N], vis[N]; struct edge{
int to, nex, w;
}e[N*2]; struct segment_tree{
int l, r, size, res1, tag;
segment_tree operator + (const segment_tree a) const{
segment_tree temp;
temp.size = size+a.size;
temp.res1 = res1+a.res1;
return temp;
}
}t[N*4][12]; int gi(){
int ans = 0, f = 1; char i = getchar();
while(i<'0' || i>'9'){ if(i == '-') f = -1; i = getchar(); }
while(i>='0' && i<='9') ans = ans*10+i-'0', i = getchar();
return ans * f;
} void add(int x, int y, int z){
e[++ecnt].to = y;
e[ecnt].w = z;
e[ecnt].nex = last[x];
last[x] = ecnt;
} void up(int x, int k){ t[x][k].res1 = t[ll(x)][k].res1+t[rr(x)][k].res1; } void dfs1(int x, int f, int deep){
size[x] = 1, dep[x] = deep, fa[x] = f;
for(int to, i=last[x];i;i=e[i].nex){
to = e[i].to;
if(to == f) continue;
pre[to] = e[i].w^pre[x], val[to] = e[i].w;
dfs1(to, x, deep+1); size[x] += size[to];
if(size[to] > size[son[x]]) son[x] = to;
}
} void dfs2(int x, int f, int tp){
top[x] = tp, id[x] = ++idx, vis[idx] = x;
if(son[x]) dfs2(son[x], x, tp);
for(int to, i=last[x];i;i=e[i].nex){
to = e[i].to;
if(to != f && to != son[x]) dfs2(to, x, to);
}
} void build(int x, int l, int r, int k){
t[x][k].l = l, t[x][k].r = r, t[x][k].size = r-l+1;
if(l == r){
if((pre[vis[l]]>>k) & 1) t[x][k].res1 = 1;
return;
}
int mid = (l+r>>1);
build(ll(x), l, mid, k), build(rr(x), mid+1, r, k); up(x, k);
} void pushdown(int x, int k){
if(t[x][k].tag == 0) return;
t[ll(x)][k].tag ^= 1, t[ll(x)][k].res1 = t[ll(x)][k].size-t[ll(x)][k].res1;
t[rr(x)][k].tag ^= 1, t[rr(x)][k].res1 = t[rr(x)][k].size-t[rr(x)][k].res1;
t[x][k].tag = 0;
} void update(int x, int l, int r, int k){
if(l <= t[x][k].l && t[x][k].r <= r){
t[x][k].res1 = t[x][k].size-t[x][k].res1;
t[x][k].tag ^= 1;
return;
}
int mid = (t[x][k].l+t[x][k].r>>1); pushdown(x, k);
if(l <= mid) update(ll(x), l, r, k);
if(mid < r) update(rr(x), l, r, k); up(x, k);
} segment_tree query(int x, int l, int r, int k){
if(l <= t[x][k].l && t[x][k].r <= r) return t[x][k];
segment_tree temp; temp.size = temp.res1 = 0;
if(r < t[x][k].l || t[x][k].r < l) return temp;
pushdown(x, k); temp.size = t[x][k].size;
return query(ll(x), l, r, k)+query(rr(x), l, r, k);
} void modify(int x, int y, int v){
if(dep[x] < dep[y]) swap(x, y);
for(int i=0;i<=10;i++)
if(((v^val[x])>>i) & 1) update(1, id[x], id[x]+size[x]-1, i);
val[x] = v;
} int ask(int xx, int yy){
int x, y, res = 0; segment_tree temp, check;
for(int i=0;i<=10;i++){
x = xx, y = yy; temp.size = temp.res1 = 0;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
temp = temp+(check=query(1, id[top[x]], id[x], i));
x = fa[top[x]];
}
if(id[x] > id[y]) swap(x, y);
temp = temp+(check=query(1, id[x], id[y], i));
res += (temp.size-temp.res1)*temp.res1*(1<<i);
}
return res;
} _int main(){
int opt, x, y, z; n = gi(), m = gi();
for(int i=1;i<n;i++) x = gi(), y = gi(), z = gi(), add(x, y, z), add(y, x, z);
dfs1(1, -1, 1); dfs2(1, -1, 1);
for(int i=0;i<=10;i++) build(1, 1, n, i); for(int i=1;i<=m;i++){
opt = gi(), x = gi(), y = gi();
if(opt == 1) cout << ask(x, y) << endl;
else z = gi(), modify(x, y, z);
}
return 0;
}

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

  1. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  2. 【BZOJ2830/洛谷3830】随机树(动态规划)

    [BZOJ2830/洛谷3830]随机树(动态规划) 题面 洛谷 题解 先考虑第一问. 第一问的答案显然就是所有情况下所有点的深度的平均数. 考虑新加入的两个点,一定会删去某个叶子,然后新加入两个深度 ...

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

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

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

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

  5. BZOJ2243 洛谷2486 [SDOI2011]染色 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2243 题目传送门 - 洛谷2486 题意概括 一棵树,共n个节点. 让你支持以下两种操作,共m次操 ...

  6. 洛谷:P1087 FBI树 P1030 求先序排列 P1305 新二叉树

    至于为啥把这三个题放到一起,大概是因为洛谷的试炼场吧,三道树的水题,首先要理解 先序中序后序遍历方法. fbi树由于数量小,在递归每个区间时,暴力跑一遍区间里的数,看看是否有0和1.至于递归的方法,二 ...

  7. 洛谷P3459 [POI2007]MEG-Megalopolis [树链剖分]

    题目传送门 MEG 题目描述 Byteotia has been eventually touched by globalisation, and so has Byteasar the Postma ...

  8. Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)

    题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...

  9. 洛谷 P5206 - [WC2019]数树(集合反演+NTT)

    洛谷题面传送门 神仙多项式+组合数学题,不过还是被我自己想出来了( 首先对于两棵树 \(E_1,E_2\) 而言,为它们填上 \(1\sim y\) 使其合法的方案数显然是 \(y\) 的 \(E_1 ...

随机推荐

  1. Red and Black(DFS深搜实现)

    Description There is a rectangular room, covered with square tiles. Each tile is colored either red ...

  2. nginx的平滑升级,不间断服务

    nginx的平滑升级,不间断服务   Nginx更新真的很快,最近nginx的1.0.5稳定版,nginx的0.8.55和nginx的0.7.69旧的稳定版本已经发布.我一项比较喜欢使用新版本的软件, ...

  3. Windows2008安装启用无线网卡

    昨天给本子换了系统来着,本来想法是好的,想在本子上安装Hyper-v来搭建多平台VPS,这样的话就能玩多个系统了,对于我自己来说对娱乐没啥兴趣,扯多了,正文 笔记本安装什么都很顺利,但是无线网卡把我难 ...

  4. server2003 必要的系统优化和安全设置

    修改远程桌面端口: Windows 2003系统中的远程终端服务是一项功能非常强大的服务,同时也成了入侵者长驻主机的通道,入侵者可以利用一些手段得到管理员账号和密码并入侵主机.下面,我们来看看如何通过 ...

  5. [C/C++] const用法详解

    const在C语言中算是一个比较新的描述符,我们称之为常量修饰符,意即其所修饰的对象为常量(immutable). 我们来分情况看语法上它该如何被使用. 1.函数体内修饰局部变量.例:void fun ...

  6. echarts 画 canvas 如果在IE8下不显示图标

    网上说法很多,可能版本问题,也有说script标签位置问题(放在body中) 不过先试已下,清除option对象中多余的逗号(,) 对象的最后一个属性后不要有逗号结尾

  7. Hessian矩阵【转】

    http://blog.sina.com.cn/s/blog_7e1ecaf30100wgfw.html 在数学中,海塞矩阵是一个自变量为向量的实值函数的二阶偏导数组成的方块矩阵,一元函数就是二阶导, ...

  8. 【刷题】洛谷 P3901 数列找不同

    题目描述 现有数列 \(A_1,A_2,\cdots,A_N\) ,Q 个询问 \((L_i,R_i)\) , \(A_{Li} ,A_{Li+1},\cdots,A_{Ri}\) 是否互不相同 输入 ...

  9. [洛谷P3975][TJOI2015]弦论

    题目大意:求一个字符串的第$k$大字串,$t$表示长得一样位置不同的字串是否算多个 题解:$SAM$,先求出每个位置可以到达多少个字串($Right$数组),然后在转移图上$DP$,若$t=1$,初始 ...

  10. POJ2187:Beauty Contest——题解

    http://poj.org/problem?id=2187 题目大意:给n个点,求点对最大距离的平方. ———————————————————— 很容易证明最大距离的点对在最大凸包上. 那么就是旋转 ...