HDU 5274 Dylans loves tree(DFS序+线段树+LCA离线查询模板+手动扩大内存)
2015-07-14 11:06
330 查看
题意:
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)(u,x)的话,就直接利用线段树进行区间更新,注意修改的值为 val[u]⊕xval[u] ⊕ x,因为val[u]val[u]和子树异或过了,如果想要修改u并更新子树,就必须先消去val[u]val[u],然后再异或上x。
如果查询(u,v)(u,v)的话,就ans=query(st[u],ed[u])⊕query(st[v],ed[v])⊕val[LCA(u,v)]ans = query(st[u], ed[u]) ⊕ query(st[v], ed[v]) ⊕ val[LCA(u,v)]
注意
这题有坑的地方就是点权可能为0,处理方法是先把所以的点权都加上1,最后再减1。mymy codecode
[code]#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,R using namespace std; typedef long long ll; const int N = 1e5+10; int n,q; int val ; vector<int> G ; int st , ed ; namespace LCA { int first , 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; }
相关文章推荐
- 剑指off-统计数字二进制位有多少个1
- 分页存储过程
- 添加Google网络地图功能
- 芸芸毕业生
- php循环
- C语言中的指针以及二级指针
- Android自定义RatingBar
- 给Xcode增加复制行、删除行快捷键的方法
- jap中PAGE,request,session和application的区别
- linux 批量清除tomcat日志
- js 处理移动端触摸事件
- 径向菜单的制作
- Wireshark数据抓包教程之Wireshark的基础知识
- nginx支持ssi使用../
- Flyme应用中心应用认领
- 针对Ruby的Selenium WebDriver安装指南
- java构造函数加载
- odoo8 pycharm debug 遇到的openerp.service.server: Evented Service (longpolling) running on 0.0.0.0:8072
- 访问一个网站需要那几个协议?
- chrome api调试插件 postman