整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


Problem

小L 和 小K 面前的圣剑由 nnn 块护符组成,分别编号为 1,2,…,n1,2,\ldots , n1,2,…,n ,有 n−1n-1n−1 条咒力线连接两块护符,形成了一个树形结构。

经过 小L 和 小K 的长时间的研究,他们发现护符之间的相互作用并不复杂。每块护符都有一个属性值,第 iii 块护符的属性值记为 viv_ivi​ 。这个值的每个二进制位上的 000 或 111 表示这块护符是否拥有特定属性。所有属性值中相同的二进制位对应的是相同的属性。

对于一系列护符(护符的集合),对于每种特定属性,统计其中包含这一属性的护符数量,如果为偶数,则这一系列护符形成了干涉,最终的属性值对应的二进制位上为 000 ,如果为奇数则干涉后剩下了一块护符的影响,对应的二进制位为 111 。也就是说, 护符集合的属性值为单个护符的属性值的异或和 。 空集的属性值定义为 000 。

现在,小L想知道,如果取出两块护符 x,yx,yx,y 间的简单路径上的所有护符,能否找到两个不相等的子集,使得两个子集的属性值相同(注意到空集也是路径上所有护符集合的子集)。同时,小K会将两块护符间的路径上的所有护符取出进行调整,将所有这些护符的属性值在某些相同二进制位上进行修改(即 000 变为 111 ,111 变为 000 ),可以看做是将所有这些护符的属性值异或上了一个值。

1≤n,q≤105,1≤x,y≤n,0≤vi,z<2301\le n,q\le 10^5,1\le x,y\le n,0\le v_i,z< 2^{30}1≤n,q≤105,1≤x,y≤n,0≤vi​,z<230

Solution

题目比较长,简而言之就是对于任意路径,看做一个数列,我们可以从中选取两个子集,这两个子集的异或和相等,我们显然可以将这两个异或和相等的自己再次异或,得到一个异或和为 000 的子集,由于路径上一定存在空集,空集异或和为 000 ,该异或和为 000 的子集就与空集配对,输出 YES,也就是说题目所求是,是否存在一个非空子集,且该子集的异或和为 000 。

考虑求异或和显然可以使用线性基。我们对于一条路径,我们可以求出它的线性基,就可以快速求得他们能够异或得到的值。

对于路径上的值,一个一个添加至线性基中,对于当前的值 vxv_xvx​,若加入后出现某子集的异或和为 000,说明加入 vxv_xvx​ 前的线性基可以异或线性表出 vxv_xvx​,此时我们使用线性基 insert vxv_xvx​ 就会失败,直接输出 YES 即可。

考虑树上路径问题,以及路径修改问题,可以使用树链剖分 + 线段树解决,但是发现时间复杂度为 O(nlog⁡5v)O(n\log^5 v)O(nlog5v),考虑能否优化。

我们发现输入的数据 vi≤230v_i\le 2^{30}vi​≤230,也就意味着线性基的维度不超过 303030,假设一条路径上有 num≥30num\ge30num≥30 个点,每次插入一个点,假设他们都线性无关,也最多能插入 303030 个点,超过 303030 个点,开始的 303030 个点由于线性无关组成了线性基,新加入的点一定能够被线性表出,直接输出 YES 即可。若前面插入的并不是全部线性无关,显然也直接输出 YES 即可。

因此我们只需要在路径长度小于 303030 的时候暴力做树链剖分,大于 303030 的时候直接输出 YES 即可。

时间复杂度 O(nlog⁡2n)O(n\log^2 n)O(nlog2n)

Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e5 + 7, maxm = maxn << 1 | 7;int n, m, s, t, ans;
int head[maxn], edge[maxm], nex[maxm], ver[maxm], tot;
int hson[maxn];
int depth[maxn];
int siz[maxn];
int fa[maxn];
int dfn[maxn], idx;
int a_after[maxn];
int top[maxn];
int id[maxn];
bool flag;
bool vis[maxn];
int v[maxn];
int q;struct Segment_tree
{struct Tree{int l, r, num, laz;}tr[maxn << 2];void pushdown(int p){if(tr[p].laz) {tr[p << 1].laz ^= tr[p].laz;tr[p << 1].num ^= tr[p].laz;tr[p << 1 | 1].laz ^= tr[p].laz;tr[p << 1 | 1].num ^= tr[p].laz;tr[p].laz = 0;}}void modify(int p, int l, int r, int v){if(tr[p].l > r || tr[p].r < l) return ;if(tr[p].l >= l && tr[p].r <= r) {tr[p].num ^= v;tr[p].laz ^= v;return ;}pushdown(p);modify(p << 1, l, r, v);modify(p << 1 | 1, l, r, v);}int query(int p, int pos){if(tr[p].l == tr[p].r) return tr[p].num;pushdown(p);int mid = tr[p].l + tr[p].r >> 1;if(pos <= mid) return query(p << 1, pos);return query(p << 1 | 1, pos);}void print(int p){if(tr[p].l == tr[p].r) printf("%d ", tr[p].num);else {pushdown(p);print(p << 1);print(p << 1 | 1);}}void build(int p, int l, int r){tr[p].l = l, tr[p].r = r;tr[p].num = 0, tr[p].laz = 0;if(l == r) return ;int mid = l + r >> 1;build(p << 1, l, mid);build(p << 1 | 1, mid + 1, r);}
}ST;void add(int x, int y)
{ver[tot] = y;nex[tot] = head[x];head[x] = tot ++ ;
}void dfs1(int x, int father, int depths)
{siz[x] = 1;fa[x] = father;depth[x] = depths;int max_son_size = -1;for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];if(y == father) continue;dfs1(y, x, depths + 1);siz[x] += siz[y];if(siz[y] > max_son_size)hson[x] = y, max_son_size = siz[y];}
}void dfs2(int x, int topfa)
{dfn[x] = ++ idx;id[idx] = x;a_after[idx] = v[x];top[x] = topfa;ST.modify(1, idx, idx, v[x]);if(hson[x] == 0) return ;dfs2(hson[x], topfa);for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];if(y == fa[x] || y == hson[x]) continue;dfs2(y, y);}
}int get_lca(int x, int y)
{while(top[x] != top[y]) {if(depth[top[x]] > depth[top[y]])x = fa[top[x]];else y = fa[top[y]];}if(depth[x] < depth[y]) return x;return y;
}struct leaner_basis
{int b[31];void init() {memset(b, 0, sizeof b);}bool insert(int x) {for(int i = 31 - 1;i >= 0; -- i){if((x & (1 << i)) == 0)continue;if(b[i] == 0){b[i] = x;return true;}x ^= b[i];}return false;}
}B;bool work(int lca, int x, int y)
{B.init();if(B.insert(ST.query(1, dfn[lca])) == 0)return true; while(x != lca) if(B.insert(ST.query(1, dfn[x])) == 0) return true;else x = fa[x];while(y != lca) if(B.insert(ST.query(1, dfn[y])) == 0) return true;else y = fa[y];return false;
}void update(int x, int y, int z)
{while(top[x] != top[y]) {if(depth[top[x]] < depth[top[y]])swap(x, y);ST.modify(1, dfn[top[x]], dfn[x], z);x = fa[top[x]];}if(dfn[x] > dfn[y])swap(x, y);ST.modify(1, dfn[x], dfn[y], z);
}signed main()
{memset(head, -1, sizeof head);scanf("%lld%lld", &n, &q);for (int i = 1; i <= n; ++ i)scanf("%lld", &v[i]);for (int i = 1; i <= n - 1; ++ i) {int x, y;scanf("%lld%lld", &x, &y);add(x, y);add(y, x);}  ST.build(1, 1, n); dfs1(1, -1, 1); dfs2(1, 1);for (int i = 1; i <= q; ++ i) {string ch;cin >> ch;if(ch == "Query") {int x, y;scanf("%lld%lld", &x, &y);int lca = get_lca(x, y);int dist = depth[x] + depth[y] - 2 * depth[lca] + 1;//经过的点数if(dist > 30)puts("YES");else {if(work(lca, x, y))puts("YES");else puts("NO");}}else {int x, y, z;scanf("%lld%lld%lld", &x, &y, &z);update(x, y, z);}}return 0;
}

Luogu P5556 圣剑护符(线性基,树链剖分,线段树)相关推荐

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  2. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  3. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  4. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  5. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

  6. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  7. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  8. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  9. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  10. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

最新文章

  1. 基于animation.css实现动画旋转特效
  2. Nuget添加新项目的问题
  3. xcode更新之后插件失效的解决办法
  4. 高德地图路线规划 时间_路线准、播报拥堵及时,这次自驾出行高德地图可算是帮了大忙...
  5. cython python3_30倍!使用Cython加速Python代码
  6. 考研数学(180°为什么等于π)
  7. 格密码教程(五):Babai‘s algorithm和求解apprCVP算法
  8. 匿名函数与自执行函数
  9. 教育部:浙江大学等35所高校新增人工智能本科专业
  10. Confluence 6 升级以后
  11. 亲个嘴竟然有这么大的学问
  12. uoj#283. 直径拆除鸡(构造)
  13. mybatis中Mapper映射
  14. stm32固件库文件
  15. vue引用阿里云iconfont使用icon图标(elementUI图标太少)
  16. 结构化思维,让你的工作有条不紊
  17. 学python编程从入门到实践方法-python自学Day07(自学书籍python编程从入门到实践)...
  18. 计算机毕业论文评阅,本科论文评阅教师评语
  19. 百度副总裁李硕:通过“一企一档”等模式提升企业智能化水平
  20. 3DMAX如何打开mat文件

热门文章

  1. 这次终于彻底理解了傅里叶变换
  2. 基于OpenCV的表格文本内容提取
  3. 语义分割网络经典:unet
  4. OpenCV深度神经网络实现人体姿态评估
  5. 深度学习模型压缩与加速综述
  6. 干货 | 抖音漫画效果解密
  7. Map Reduce Shuffle
  8. scroll-苹果滑动卡顿
  9. CentOS7.4下DNS服务器软件BIND安装及相关的配置(一)
  10. web初级开发的那些坑