[Contest20171102]简单数据结构题
2017-11-02 21:39
127 查看
给一棵$n$个点的数,点权开始为$0$,有$q$次操作,每次操作选择一个点,把周围一圈点点权$+1$,在该操作后你需要输出当前周围一圈点点权的异或和。
由于输出量较大,设第$i$个询问输出为$ans_i$,你只需要输出$\sum\limits_{i=1}^qans_i(i^2+i)\mod (10^9+7)$
异或和的话,用trie存比较方便
具体点:每个节点建一棵trie,存它的所有儿子的权值,trie上的tag维护数字数量和当前子树内的异或和
①对所有儿子$+1$
其实就是把一棵trie中的所有数字$+1$
为了模拟加法,我们的trie是从低位开始建的
当前位可能是$0$或$1$,如果是$0$,$+1$后会变成$1$,如果是$1$,$+1$后会变成$0$并进位
那么我们直接交换当前trie节点的左右儿子,并递归进入$0$儿子
修改过程中顺便维护异或和
②对父亲$+1$
为了知道一个节点当前的值,我们需要两个标记
$d_{x}$表示节点$x$的增值
$ds_x$表示节点$x$的所有儿子的增值
那么一个节点当前的值就是$d_x+ds_{fa_x}$
所以我们对$x$的父亲$+1$时,只需要在$fa_{fa_x}$的trie中删除$d_{fa_x}$,让$d_x+1$,然后再插入回去
于是就愉快地解决啦
![](https://images2017.cnblogs.com/blog/1213476/201711/1213476-20171102213546513-905872332.png)
ahhhhhhhhhhhhhhhh结弦好可爱~~~~~~~
由于输出量较大,设第$i$个询问输出为$ans_i$,你只需要输出$\sum\limits_{i=1}^qans_i(i^2+i)\mod (10^9+7)$
异或和的话,用trie存比较方便
具体点:每个节点建一棵trie,存它的所有儿子的权值,trie上的tag维护数字数量和当前子树内的异或和
①对所有儿子$+1$
其实就是把一棵trie中的所有数字$+1$
为了模拟加法,我们的trie是从低位开始建的
当前位可能是$0$或$1$,如果是$0$,$+1$后会变成$1$,如果是$1$,$+1$后会变成$0$并进位
那么我们直接交换当前trie节点的左右儿子,并递归进入$0$儿子
修改过程中顺便维护异或和
②对父亲$+1$
为了知道一个节点当前的值,我们需要两个标记
$d_{x}$表示节点$x$的增值
$ds_x$表示节点$x$的所有儿子的增值
那么一个节点当前的值就是$d_x+ds_{fa_x}$
所以我们对$x$的父亲$+1$时,只需要在$fa_{fa_x}$的trie中删除$d_{fa_x}$,让$d_x+1$,然后再插入回去
于是就愉快地解决啦
![](https://images2017.cnblogs.com/blog/1213476/201711/1213476-20171102213546513-905872332.png)
ahhhhhhhhhhhhhhhh结弦好可爱~~~~~~~
#include<stdio.h> #define ll long long struct edge{ int to,nex; }e[1000010]; int h[500010],d[500010],sd[500010],fa[500010],root[500010],ch[20000010][2],siz[20000010],xorsum[20000010],tot; void add(int a,int b){ tot++; e[tot].to=b; e[tot].nex=h[a]; h[a]=tot; } void pushup(int x){ xorsum[x]=((xorsum[ch[x][0]]^xorsum[ch[x][1]])<<1)|(siz[ch[x][1]]&1); } void insert(int&x,int v,int p){ if(x==0){ tot++; x=tot; } siz[x]++; if(p==19)return; insert(ch[x][(v>>p)&1],v,p+1); pushup(x); } void dfs(int x){ for(int i=h[x];i;i=e[i].nex){ if(e[i].to!=fa[x]){ fa[e[i].to]=x; dfs(e[i].to); insert(root[x],0,0); } } } void swap(int&a,int&b){a^=b^=a^=b;} void plus(int x,int p){ if(x==0||p==19)return; swap(ch[x][0],ch[x][1]); plus(ch[x][0],p+1); pushup(x); } void erase(int&x,int v,int p){ siz[x]--; if(p==19){ if(siz[x]==0)x=0; return; } erase(ch[x][(v>>p)&1],v,p+1); if(siz[x]==0) x=0; else pushup(x); } ll query(int x){ sd[x]++; plus(root[x],0); if(x==1)return xorsum[root[x]]; if(fa[x]==1){ d[1]++; return xorsum[root[x]]^d[1]; } erase(root[fa[fa[x]]],d[fa[x]]+sd[fa[fa[x]]],0); d[fa[x]]++; insert(root[fa[fa[x]]],d[fa[x]]+sd[fa[fa[x]]],0); return xorsum[root[x]]^(d[fa[x]]+sd[fa[fa[x]]]); } int main(){ int n,q,i,a,b; ll ans=0; scanf("%d%d",&n,&q); for(i=1;i<n;i++){ scanf("%d%d",&a,&b); add(a,b); add(b,a); } tot=0; dfs(1); for(i=1;i<=q;i++){ scanf("%d",&a); ans=(ans+query(a)*(i*(ll)i+(ll)i))%1000000007; } printf("%lld",ans); }
相关文章推荐
- 数据结构之广度优先算法的Python简单实现
- 数据结构 单链表简单实现
- 数据结构之栈的简单实现
- 数据结构实验之串一:KMP简单应用
- 【数据结构与算法】(六) c 语言实现简单的二叉树静态创建及先序、中序、后序遍历
- 简单来说 数据结构有哪些? 存储方式上:链表形式,数组,
- 数据结构与算法——基数排序简单Java实现
- 数据结构(Java语言)——LinkedList简单实现
- 数据结构与算法学习笔记——堆栈及其应用(10以内简单四则计算器)
- SQL Server AB表同结构的简单数据同步存储过程
- 数据结构——用栈解决简单迷宫问题
- 数据结构杂谈(二)简单有趣的地精排序Gnome sort
- [数据结构]图基于邻接矩阵的BFS与DFS的C语言简单实现
- 树结构数据的展示和编辑-zTree树插件的简单使用
- 【数据结构与算法】String 的简单实现
- 数据结构实验之串一:KMP简单应用
- 数据结构实验一------构建简单的手机通讯录(C语言)
- 算法与数据结构基础5:C++栈的简单实现
- 数据结构经典算法学习之八枚银币(简单决策树)
- 导出数据库数据的方法,适合简单的数据库表格结构