HDU 5274 Dylans loves tree(DFS序+线段树+LCA离线查询模板+手动扩大内存)
来源:互联网 发布:仓位在线软件 编辑:程序博客网 时间:2024/06/06 09:43
题意:
Dylans有一棵N个点的树。每个点有点权。树上节点标号为1∼N。
他得到了Q个询问,形式如下:
①0 x y:把第x个点的点权修改为y。
②1 x y:对于x∼y路径上的每一种点权,是否都出现偶数次?
保证每次询问的路径上最多只有一种点权的出现次数是奇数次。
1≤N,Q≤100000, 点权A[i]∈N,且都 ≤100000
解析:
这题比较难啊,参考了一下网络上面的题解。
如果一个数组, 只有一个数字出现奇数次, 有什么比较好的方法 快速找出这个数字?
答:因为两个相同的数异或和等于0,所以把所有的数字异或在一起,异或和就是,出现的奇数数字。
那么能想到用线段树来维护异或和的方法,来解决这一题。有一种经典的将树上的点转化成序列的方法,我们用dfs遍历这棵树,那么对于一个节点,他一点比他的子树即子节点先访问到,且当他的最后一个子节点的所有子树也都访问完时,这中间访问的节点一定都是他的子树。那么我们可以在访问时做一下记录,每个点首先被访问的index和结束时的index,那么这中间的便是他的子树。
转换成序列之后就能利用线段树进行维护了。
具体做法就是:
先用dfs一遍求出,到每个点的dfs序,记录下该dfs序,以便之后用dfs维护。
然后构建一个线段树,来表示每个区间的异或和。
然后修改(u,x) 的话,就直接利用线段树进行区间更新,注意修改的值为val[u]⊕x ,因为val[u] 和子树异或过了,如果想要修改u并更新子树,就必须先消去val[u] ,然后再异或上x。
如果查询(u,v) 的话,就ans=query(st[u],ed[u])⊕query(st[v],ed[v])⊕val[LCA(u,v)]
注意
这题有坑的地方就是点权可能为0,处理方法是先把所以的点权都加上1,最后再减1。
#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<set>#define ls o<<1#define rs o<<1|1#define lson o<<1,L,M#define rson o<<1|1,M+1,Rusing namespace std;typedef long long ll;const int N = 1e5+10;int n,q;int val[N];vector<int> G[N];int st[N], ed[N];namespace LCA { int first[N], node[N*2], deep[N*2]; struct ST { int dp[N*2][20]; void init(int n) { for(int i = 1; i <= n; i++) dp[i][0] = i; for(int k = 1; (1 << k) <= n; k++) { for(int i = 1; i <= n-(1<<k)+1; i++) { int a = dp[i][k-1]; int b = dp[i+(1<<(k-1))][k-1]; dp[i][k] = (deep[a] < deep[b]) ? a : b; } } } int query(int L, int R) { int len = (R-L+1), k = 0; while((1<<(k+1)) <= len) k++; int a = dp[L][k], b = dp[R-(1<<k)+1][k]; return (deep[a] < deep[b]) ? a : b; } } table; int clock, index; void dfs(int u, int pre, int de) { st[u] = ++index; node[++clock] = u; deep[clock] = de; first[u] = clock; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v == pre) continue; dfs(v, u, de+1); node[++clock] = u; deep[clock] = de; } ed[u] = index; } void init(int n) { clock = 0; index = 0; dfs(1, -1, 0); table.init(2*n-1); } int lca(int u, int v) { int L = first[u], R = first[v]; if(L > R) swap(L, R); return node[table.query(L, R)]; }}struct Node{ int val, set;} node[N<<2];inline void pushUp(Node& fa, Node& Ls, Node& Rs){ fa.val = (Ls.val ^ Rs.val);}inline void pushDown(Node& fa, Node& Ls, Node& Rs){ if (fa.set) { Ls.val ^= fa.set; Ls.set ^= fa.set; Rs.val ^= fa.set; Rs.set ^= fa.set; fa.set = 0; }}void modify(int o, int L, int R, int ql, int qr, int delta){ if (ql <= L && R <= qr) { node[o].val ^= delta; node[o].set ^= delta; return; } int M = (L+R)/2; pushDown(node[o], node[ls], node[rs]); if (ql <= M) modify(lson, ql, qr, delta); if (qr > M) modify(rson, ql, qr, delta); pushUp(node[o], node[ls], node[rs]);}int query(int o, int L, int R,int ql, int qr){ if(ql<=L && R<=qr){ return node[o].val; } int M = (L+R)/2; pushDown(node[o], node[ls], node[rs]); int ret = 0; if(qr <= M) ret ^= query(lson,ql,qr); if(ql > M) ret ^= query(rson,ql,qr); return ret;}void addEdge(int u, int v) { G[u].push_back(v);}int MAIN() { int T; scanf("%d", &T); while(T--) { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) G[i].clear(); int u, v; for(int i=1;i<=n-1;i++){ scanf("%d%d",&u,&v); addEdge(u, v); addEdge(v, u); } for(int i=1;i<=n;i++){ scanf("%d",&val[i]); val[i]++; } LCA::init(n); memset(node,0,sizeof(node)); for(int i=1;i<=n;i++) modify(1,1,n,st[i],ed[i],val[i]); while(q--) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(a == 0) { c++; modify(1,1,n,st[b],ed[b],val[b]^c); val[b] = c; }else { int wt1 = query(1,1,n,st[b],st[b]); int wt2 = query(1,1,n,st[c],st[c]); int wt3 = val[LCA::lca(b,c)]; int ans = wt1^wt2^wt3; printf("%d\n",ans-1); } } } return 0;}const int main_stack = 16;char my_stack[128<<20];int main() { __asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory"); __asm__("movl %%eax, %%esp;\n"::"a"(my_stack + sizeof(my_stack) - main_stack):"%esp"); MAIN(); __asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp"); return 0;}
- HDU 5274 Dylans loves tree(DFS序+线段树+LCA离线查询模板+手动扩大内存)
- hdu5274 Dylans loves tree LCA+线段树
- HDU 5274 Dylans loves tree(LCA+dfs时间戳+成段更新 OR 树链剖分+单点更新)
- 【线段树】 HDOJ 5274 Dylans loves tree
- HDU5274 Dylans loves tree(树链剖分线段树)
- hdu 5274 Dylans loves tree 树剖
- HDU 5274 Dylans loves tree 树链剖分(水)
- HDOJ 5274 Dylans loves tree
- hdu 5274 Dylans loves tree && BestCoder Round #45
- HDU 5273 Dylans loves sequence(线段树求逆序数对+离散化)
- HDU 3966 Aragorn's Story(树链剖分+线段树区间更新+手动扩大内存)
- HDU 5266 pog loves szh III (线段树+LCA)
- hdu5274 Dylans loves tree
- HDU5274.Dylans loves tree
- hdu5274 - Dylans loves tree(树链剖分)
- HDU 5196 DZY Loves Inversions(离线+线段树)
- HDU 5272 Dylans loves numbers
- hdu 5273 Dylans loves sequence
- 欢迎使用CSDN-markdown编辑器
- 5.斐波那契数组:循环和递归;输入n时判断该数是几:(for循环和递归写) 1 1 2 3 5 8 13 21 34
- 路由器的疑问???
- linux下C获取系统时间的方法
- 剑指off-统计数字二进制位有多少个1
- HDU 5274 Dylans loves tree(DFS序+线段树+LCA离线查询模板+手动扩大内存)
- 【leetcode】20. Valid Parentheses
- IOS风格的时间选择器在安卓中的简单实现
- loadrunner中对https证书的配置
- vs2010安装包制作
- sonar代码检查
- 如何将U盘FAT32转NTFS
- wsdd方式发布web service
- 安卓4大组件