bzoj 3757 苹果树(树上莫队算法)
【题意】
有若干个询问,询问路径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 苹果树(树上莫队算法)的更多相关文章
- BZOJ.3757.苹果树(树上莫队)
题面链接 /* 代码正确性不保证..(不过交了SPOJ没WA T了最后一个点) 在DFS序做莫队 当一个点不是另一个点的LCA时,需要加上它们LCA的贡献 */ #include <cmath& ...
- 【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)
2016-05-09 UPD:学习了新的DFS序列分块,然后发现这个东西是战术核导弹?反正比下面的树分块不知道要快到哪里去了 #include<cmath> #include<cst ...
- SPOJ COT2 Count on a tree II 树上莫队算法
题意: 给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问. 每次询问路径\(u \to v\)上有多少个权值不 ...
- [BZOJ3757]苹果树(树上莫队)
树上莫队共有三种写法: 1.按DFS序列分块,和普通莫队类似.常数大,不会被卡. 2.按块状树的方式分块.常数小,会被菊花图卡到O(n). 3.按[BZOJ1086]王室联邦的方式分块.常数小,不会被 ...
- BZOJ 3339: Rmq Problem 莫队算法
3339: Rmq Problem 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=3339 Description n个数,m次询问l,r ...
- 【BZOJ】4358: permu 莫队算法
[题意]给定长度为n的排列,m次询问区间[L,R]的最长连续值域.n<=50000. [算法]莫队算法 [题解]考虑莫队维护增加一个数的信息:设up[x]表示数值x往上延伸的最大长度,down[ ...
- uoj #58. 【WC2013】糖果公园(树上莫队算法+修改操作)
[题目链接] http://uoj.ac/problem/58 [题意] 有一棵树,结点有自己的颜色,若干询问:u,v路径上的获益,并提供修改颜色的操作. 其中获益定义为Vc*W1+Vc*W2+…+V ...
- 「日常训练&知识学习」莫队算法(二):树上莫队(Count on a tree II,SPOJ COT2)
题意与分析 题意是这样的,给定一颗节点有权值的树,然后给若干个询问,每次询问让你找出一条链上有多少个不同权值. 写这题之前要参看我的三个blog:Codeforces Round #326 Div. ...
- BZOJ 3757 苹果树 ——莫队算法
挺好的一道题目,怎么就没有版权了呢?大数据拍过了,精神AC.... 发现几种颜色这性质比较垃圾,不可加,莫队硬上. %了一发popoqqq大神的博客, 看了一波VFK关于糖果公园的博客, 又找了wjm ...
随机推荐
- TaskController.java-20160611
package main.java.com.zte.controller.system; import java.io.PrintWriter;import java.util.ArrayList;i ...
- 应用scikit-learn做文本分类
文本挖掘的paper没找到统一的benchmark,只好自己跑程序,走过路过的前辈如果知道20newsgroups或者其它好用的公共数据集的分类(最好要所有类分类结果,全部或取部分特征无所谓)麻烦留言 ...
- Docker仓库搭建(Registry + Portus)
1.更新系统: yum update -y 2. 安装docker-compos yum -y install epel-release #pip安装包在epel源中 yum -y inst ...
- 怎样在Ubuntu系统安装可用的QQ
http://jingyan.baidu.com/article/9f63fb91d1f6bbc8400f0e1c.html
- Android项目真的要去做混淆(加密)处理
以前做项目做是懒得混淆代码,因为要处理各种第三方的混淆东西,像友盟里面加了第三方库,又要特殊处理混淆操作,所以很麻烦,也懒得去做混淆操作,so 你懂的:但今天我用一个反编译工具,发现一个很可怕的事情 ...
- css默认被后代inherite的属性列表
css中的属性大部分都可以被继承,但是也有众多不能被继承,比如display, position,,left,right,top,bottom,float,width,border-color,bor ...
- UVa 1225 Digit Counting
题意:给出n,将前n个整数顺次写在一起,统计各个数字出现的次数. 用的最笨的办法--直接统计-- 后来发现网上的题解有先打表来做的 #include<iostream> #include& ...
- [转载]mysql的binlog安全删除
[转载]mysql的binlog安全删除 理论上,应该在配置文件/etc/my.cnf中加上binlog过期时间的配置项,expire_logs_days = 10 但是如果没有加这一项,随着产生越 ...
- 20160129.CCPP体系详解(0008天)
程序片段(01):函数.c+call.c+测试.cpp 内容概要:函数 ///函数.c #include <stdio.h> #include <stdlib.h> //01. ...
- 【自动化测试】Selenium - 定位
http://easonhan007.github.io/selenium/2014/01/10/se-secret_01/ 你应该遵照这个规则来选择定位元素的属性.name > id > ...