【题意】

有若干个询问,询问路径u,v上的颜色总数,另外有要求a,b,意为将a颜色看作b颜色。

【思路】

vfk真是神系列233。

Quote:

用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))上的结点,将它们的存在性取反即可。

                                          from vfleaking

设目前指针处于a,b,且now为已经得到的T(curV,curU)的统计答案,此次询问为u,v,则我们使a->u,b->v,设计一个vis标记,路上取反标记并更新now,即xor T(curV,targetV),最后还要取反lca(u,v)才是一个完整的u->v路径。

【代码】

 #include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; typedef long long ll;
const int N = 4e5+;
const int D = ; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct Edge {
int v,nxt;
}e[N];
int en=,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
} int n,m,B,B_cnt,now,dfsc,dfn[N],ans[N];
int pos[N],a[N],cnt[N],vis[N],fa[N][D],dep[N],st[N],top; struct Node
{
int id,l,r,a,b;
bool operator < (const Node& rhs) const
{
return pos[l]<pos[rhs.l] || (pos[l]==pos[rhs.l]&&dfn[r]<dfn[rhs.r]);
}
} q[N]; int dfs(int u)
{
FOR(i,,D-)
fa[u][i]=fa[fa[u][i-]][i-];
int size=;
dfn[u]=++dfsc;
trav(u,i)
{
int v=e[i].v;
if(v!=fa[u][]) {
fa[v][]=u;
dep[v]=dep[u]+;
size+=dfs(v);
if(size>=B) {
B_cnt++;
while(size--)
pos[st[top--]]=B_cnt;
}
}
}
st[++top]=u;
return size+;
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v];
FOR(i,,D-)
if((<<i)&t) u=fa[u][i];
if(u==v) return u;
for(int i=D-;i>=;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][];
}
void upd(int u)
{
if(!vis[u]) {
vis[u]=;
now+=(++cnt[a[u]])==;
} else {
vis[u]=;
now-=(--cnt[a[u]])==;
}
}
void work(int u,int v)
{
while(u!=v)
{
if(dep[u]<dep[v]) swap(u,v);
upd(u); u=fa[u][];
}
}
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
n=read(),m=read();
B=sqrt(n);
FOR(i,,n) a[i]=read();
int rt,u,v;
FOR(i,,n) {
u=read(),v=read();
if(!u) rt=v;
else if(!v) rt=u;
else adde(u,v),adde(v,u);
}
dfs(rt);
B_cnt++;
while(top) pos[st[top--]]=B_cnt;
FOR(i,,m) {
q[i].l=read(),q[i].r=read();
q[i].a=read(),q[i].b=read();
q[i].id=i;
if(dfn[q[i].l]>dfn[q[i].r]) swap(q[i].l,q[i].r);
}
sort(q+,q+m+); work(q[].l,q[].r);
int lc=lca(q[].l,q[].r);
upd(lc);
ans[q[].id]=now;
ans[q[].id]-=(q[].a!=q[].b)&&(cnt[q[].a]&&cnt[q[].b]);
upd(lc); FOR(i,,m) {
work(q[i-].l,q[i].l);
work(q[i-].r,q[i].r);
lc=lca(q[i].l,q[i].r);
upd(lc);
ans[q[i].id]=now;
ans[q[i].id]-=(q[i].a!=q[i].b)&&(cnt[q[i].a]&&cnt[q[i].b]);
upd(lc);
} FOR(i,,m)
printf("%d\n",ans[i]);
return ;
}

bzoj 3757 苹果树(树上莫队算法)的更多相关文章

  1. BZOJ.3757.苹果树(树上莫队)

    题面链接 /* 代码正确性不保证..(不过交了SPOJ没WA T了最后一个点) 在DFS序做莫队 当一个点不是另一个点的LCA时,需要加上它们LCA的贡献 */ #include <cmath& ...

  2. 【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)

    2016-05-09 UPD:学习了新的DFS序列分块,然后发现这个东西是战术核导弹?反正比下面的树分块不知道要快到哪里去了 #include<cmath> #include<cst ...

  3. SPOJ COT2 Count on a tree II 树上莫队算法

    题意: 给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问. 每次询问路径\(u \to v\)上有多少个权值不 ...

  4. [BZOJ3757]苹果树(树上莫队)

    树上莫队共有三种写法: 1.按DFS序列分块,和普通莫队类似.常数大,不会被卡. 2.按块状树的方式分块.常数小,会被菊花图卡到O(n). 3.按[BZOJ1086]王室联邦的方式分块.常数小,不会被 ...

  5. BZOJ 3339: Rmq Problem 莫队算法

    3339: Rmq Problem 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=3339 Description n个数,m次询问l,r ...

  6. 【BZOJ】4358: permu 莫队算法

    [题意]给定长度为n的排列,m次询问区间[L,R]的最长连续值域.n<=50000. [算法]莫队算法 [题解]考虑莫队维护增加一个数的信息:设up[x]表示数值x往上延伸的最大长度,down[ ...

  7. uoj #58. 【WC2013】糖果公园(树上莫队算法+修改操作)

    [题目链接] http://uoj.ac/problem/58 [题意] 有一棵树,结点有自己的颜色,若干询问:u,v路径上的获益,并提供修改颜色的操作. 其中获益定义为Vc*W1+Vc*W2+…+V ...

  8. 「日常训练&知识学习」莫队算法(二):树上莫队(Count on a tree II,SPOJ COT2)

    题意与分析 题意是这样的,给定一颗节点有权值的树,然后给若干个询问,每次询问让你找出一条链上有多少个不同权值. 写这题之前要参看我的三个blog:Codeforces Round #326 Div. ...

  9. BZOJ 3757 苹果树 ——莫队算法

    挺好的一道题目,怎么就没有版权了呢?大数据拍过了,精神AC.... 发现几种颜色这性质比较垃圾,不可加,莫队硬上. %了一发popoqqq大神的博客, 看了一波VFK关于糖果公园的博客, 又找了wjm ...

随机推荐

  1. kafka安装及常用命令

    kafka是一个开源的分布式消息队列 他提供可靠的集群容错机制,并保证故障切换时的数据完整性. 无论从性能.可靠性.易用性都强过ActiveMQ(client的API感觉还是不如ActiveMQ好用, ...

  2. [转载]破解TexturePacker加密资源

    最近我们要开一个新项目,UI与交互打算借鉴当前正火的<圣火英雄传>,程序开发为了和美术制作并行,打算用圣火的资源暂代使用.我解压圣火apk,发现用TexturePacker命令行无法把它的 ...

  3. mysql高可用方案比较

    详见:High Availability Database Tools http://www.acquia.com/blog/high-availability-database-tools

  4. 《OD学hive》第六周20160731

    一.hive的压缩 1. hadoop的压缩 1)为什么需要压缩 MapReduce的性能瓶颈:网络IO.磁盘IO 数据量:对于MapReduce的优化,最主要.根本就是要能够减少数据量 Combin ...

  5. hdfs工作原理

    一.NameNode和DataNode (1)NameNode NameNode的作用是管理文件目录结构,是管理数据节点的.NameNode维护两套数据:一套是文件目录与数据块之间的关系,另一套是数据 ...

  6. Windows pyqt4 bat自动转换UI文件-->.pyw文件

    /***************************************************************************** * Windows pyqt4 bat自动 ...

  7. MySQL Database on Azure - 利用PowerShell快速创建使用数据库服务

    如果您的应用需要通过脚本快速创建一个或多个MySQL数据库,MySQL Database on Azure目前开放了对于PowerShell的支持,可以帮助您快速利用自动化脚本进行数据库服务的创建.管 ...

  8. HDU Sky数 2097

    解题思路:类比求出10进制数各个位上的数字之和,求出12进制和16进制上的数. #include<cstdio> #include<cstring> #include<a ...

  9. web app 页面旋转整体样式问题

    $(window).bind("orientationchange", function (event) { if (event.orientation) { //portrait ...

  10. linux系统上Mysql数据库导入导出操作

    需求:把MySQL数据库目录中的dz数据库备份到/home/dz_bak.sql ,然后再新建一个数据库dzbak,最后把/home/dz_bak.sql 导入到数据库dzbak中.操作如下:以下操作 ...