3757: 苹果树 树上莫队 位运算技巧
来源:互联网 发布:台湾驱动透视源码 编辑:程序博客网 时间:2024/04/30 04:49
引用Vfleaking神犇[WC2013]糖果公园的一些题解。
本题也可以如此解决,神奇的莫队:
上一次询问用(curV, curU, curTi)表示,并且我们还保留了
visited[v]:v节点在不在curV到curU的路径上
col[v]:v节点的颜色(原题好像是糖果来着?我就叫颜色了。)
occur[c]:颜色c在curV到curU的路径上出现的次数
outcome:当前的答案。
这些信息。
现在又来了一个神奇的询问!(targetV, targetU, targetTi)
那么将curV 移动到targetV去,curU移动到targetU, 时间curTi移动到targetTi上去,然后再回答询问。
先说时间的移动好了,这个比较简单。
预处理出来每个修改在修改之前的颜色。(修改之后的颜色是输入)
如果targetTi > curTi
那么不停地curTi++,执行当前修改。
如果targetTi <= curTi
那么不停地curTi++,撤销当前修改,利用刚才的预处理。
给一个节点改变颜色的方式是,如果visited了,就XXXXXX,如果没visited,就XXXXXX。讨论一下就行了囧。
然后是节点的移动。
好像巨纠结啊囧!!!
我只会sb方法,求神犇赐教。
用S(v, u)代表 v到u的路径上的结点的集合。
用root来代表根结点,用lca(v, u)来代表v、u的最近公共祖先。
那么
S(v, u) = S(root, v) xor S(root, u) xor lca(v, u)
其中xor是集合的对称差。
简单来说就是节点出现两次消掉。
lca很讨厌,于是再定义
T(v, u) = S(root, v) xor S(root, u)
观察将curV移动到targetV前后T(curV, curU)变化:
T(curV, curU) = S(root, curV) xor S(root, curU)
T(targetV, curU) = S(root, targetV) xor S(root, curU)
取对称差:
T(curV, curU) xor T(targetV, curU)= (S(root, curV) xor S(root, curU)) xor (S(root, targetV) xor S(root, curU))
由于对称差的交换律、结合律:
T(curV, curU) xor T(targetV, curU)= S(root, curV) xor S(root, targetV)
两边同时xor T(curV, curU):
T(targetV, curU)= T(curV, curU) xor S(root, curV) xor S(root, targetV)
发现最后两项很爽……哇哈哈
T(targetV, curU)= T(curV, curU) xor T(curV, targetV)
(有公式恐惧症的不要走啊 T_T)
也就是说,更新的时候,xor T(curV, targetV)就行了。
即,对curV到targetV路径(除开lca(curV, targetV))上的结点,将它们的存在性取反即可。
我之前说的visited[]、occur[]、outcome的定义并不方便,因为有个lca搀和。
干脆用这仨记录集合T(curV, curU)的情况,更加方便处理。
我觉得还是上代码比较有亲切感。
verXor函数的作用是将一个结点的存在性取反。
val 即题目中的V。
sumCoe是题目中的W的前缀和。
father[v][0]是结点v的父亲。
depth[v]是结点的深度。
T_T为什么我写的这么慢。。。
#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>using namespace std;int n,m,cnt,top,ans,scc,ind,root,block;int head[50005],dfn[50005],s[50005],c[50005],pos[50005],stack[50005],deep[50005],fa[50005][17];int next[100005],list[100005];bool vis[50005];struct node {int u,v,a,b,id,ans;} a[100005];inline int read(){ int a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f;}inline void insert(int x,int y){ next[++cnt]=head[x]; head[x]=cnt; list[cnt]=y;}inline bool cmp(node a,node b){ return pos[a.u]==pos[b.u]?dfn[a.v]<dfn[b.v]:pos[a.u]<pos[b.u];}inline bool cmp0(node a,node b){ return a.id<b.id;}int dfs(int x){ int size=0; dfn[x]=++ind; for (int i=1;(1<<i)<=deep[x];i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for (int i=head[x];i;i=next[i]) if (list[i]!=fa[x][0]) { fa[list[i]][0]=x; deep[list[i]]=deep[x]+1; size+=dfs(list[i]); if (size>=block) { scc++; for (int j=1;j<=size;j++) pos[stack[top--]]=scc; size=0; } } stack[++top]=x; return size+1;}inline int lca(int x,int y){ if (deep[x]<deep[y]) swap(x,y); int t=deep[x]-deep[y]; for (int i=0;(1<<i)<=t;i++) if (t&(1<<i)) x=fa[x][i]; for (int i=16;~i;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return x==y?x:fa[x][0];}inline void rever(int x){ if (!vis[x]) {vis[x]=1; s[c[x]]++; if (s[c[x]]==1) ans++;} else {vis[x]=0; s[c[x]]--; if (s[c[x]]==0) ans--;}}inline void solve(int u,int v){ while (u!=v) if (deep[u]>deep[v]) rever(u),u=fa[u][0]; else rever(v),v=fa[v][0];}int main(){ n=read(); m=read(); block=(int)(sqrt(n)); for (int i=1;i<=n;i++) c[i]=read(); for (int i=1;i<=n;i++) { int u=read(),v=read(); if (!u) root=v; else if (!v) root=u; else insert(u,v),insert(v,u); } dfs(root); scc++; while (top) pos[stack[top--]]=scc; for (int i=1;i<=m;i++) { a[i].u=read(); a[i].v=read(); a[i].id=i; a[i].a=read(); a[i].b=read(); if (dfn[a[i].u]>dfn[a[i].v]) swap(a[i].u,a[i].v); } sort(a+1,a+m+1,cmp); int t=lca(a[1].u,a[1].v); solve(a[1].u,a[1].v); rever(t); a[1].ans=ans; if (s[a[1].a]&&s[a[1].b]&&a[1].a!=a[1].b) a[1].ans--; rever(t); for (int i=2;i<=m;i++) { solve(a[i-1].u,a[i].u); solve(a[i-1].v,a[i].v); int t=lca(a[i].u,a[i].v); rever(t); a[i].ans=ans; if (s[a[i].a]&&s[a[i].b]&&a[i].a!=a[i].b) a[i].ans--; rever(t); } sort(a+1,a+m+1,cmp0); for (int i=1;i<=m;i++) printf("%d\n",a[i].ans); return 0;}
- 3757: 苹果树 树上莫队 位运算技巧
- BZOJ 3757 苹果树 树上莫队
- BZOJ 3757 苹果树 树上莫队
- bzoj 3757: 苹果树(树上莫队)
- bzoj 3757 苹果树(树上莫队)
- [BZOJ 3757]苹果树:树上莫队
- BZOJ_P3757 苹果树(树上莫队+LCA)
- jzoj 3360. 【NOI2013模拟】苹果树 树上莫队
- 位运算应用技巧
- 位运算应用技巧
- 位运算的技巧
- 位运算(技巧)
- 位运算各种技巧
- 位运算应用技巧
- 位运算常用技巧
- 位运算 技巧
- 位运算技巧
- 各种位运算技巧
- poj 2492 A Bug's Life 并查集
- Linux曲径通幽:常用命令(压缩解压命令)
- 正确使用SQL Server中的count()函数
- 使用actionBar,实现ViewPagerIndicator的效果(ViewParger指示器)
- WordPress给用户添加联系方式
- 3757: 苹果树 树上莫队 位运算技巧
- Linux学习之路——使用su用户身份无法切换的问题
- Delphi CompareValue函数的使用
- WordPress给附件添加属性
- 【POJ 2983】Is the Information Reliable?(差分约束系统)
- TIPTOP ERP不完全实施开发手册
- Parencodings(POJ_1068)
- C#获取DLL、程序路径,C#获取桌面、收藏夹等特殊系统路径
- 2016蓝桥杯假期任务之《世纪末的星期》