构建:像线性的莫队那样,依旧是按sqrt(n)为一块分块。

 int dfs(int x){
int size=;
dfn[x]=++ind;
for (int i=;i<=;i++)
if (bin[i]<=deep[x])
fa[x][i]=fa[fa[x][i-]][i-];
else break;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (pur!=fa[x][]){
fa[pur][]=x;
deep[pur]=deep[x]+;
size+=dfs(pur);
if (size>=blo){
blonum++;
for (int k=;k<=size;k++)
belong[st[top--]]=blonum;
size=;
}
}
}
st[++top]=x;
return size+;
}

然后呢,我们可以发现一些树上莫队的性质:

用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) xorS(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)
也就是说,更新的时候,xor T(curV, targetV)就行了。
即,对curV到targetV路径(除开lca(curV, targetV))上的结点,将它们的存在性取反即可。
 
按照以上方式,我们就可以每次从u1走到u2,v1走到v2,然后要求query的时候对他们的公共祖先的存在性取反,然后求完答案后再取反回去。
 
bzoj3757 苹果树
 #include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <vector>
#include <functional>
#include <ctime>
#include <cstdlib>
#include <sstream>
#include <set>
#include <deque>
#define Rep(i, l, r) for (int i = l; i <= r; ++i)
#define Req(i, l, r) for (int i = l; i >= r; --i)
#define N 100005
int tot,go[N],next[N],first[N],dfn[N],belong[N];
int st[N],res[N],n,m,x,y,fa[N][],bin[],col[N],ans,ind,deep[N],blo,blonum;
int top,pd[N],root;
struct op{
int u,v,id,a,b;
}q[N];
int p[N];
void insert(int x,int y){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
}
void add(int x,int y){
insert(x,y);
insert(y,x);
}
bool cmp(op q,op w){
if (belong[q.u]==belong[w.u]) return dfn[q.v]<dfn[w.v];
else return belong[q.u]<belong[w.u];
}
int dfs(int x){
int size=;
dfn[x]=++ind;
for (int i=;i<=;i++)
if (bin[i]<=deep[x])
fa[x][i]=fa[fa[x][i-]][i-];
else break;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (pur!=fa[x][]){
fa[pur][]=x;
deep[pur]=deep[x]+;
size+=dfs(pur);
if (size>=blo){
blonum++;
for (int k=;k<=size;k++)
belong[st[top--]]=blonum;
size=;
}
}
}
st[++top]=x;
return size+;
}
void reverse(int x){
if (pd[x]) {
p[col[x]]--;
pd[x]=;
if (p[col[x]]==) ans--;
}
else{
p[col[x]]++;
pd[x]=;
if (p[col[x]]==) ans++;
}
}
void solve(int u,int v){
while (u!=v){
if (deep[u]>deep[v]) reverse(u),u=fa[u][];
else reverse(v),v=fa[v][];
}
}
int lca(int x,int y){
if (deep[x]<deep[y]) std::swap(x,y);
int t=deep[x]-deep[y];
for (int i=;i>=;i--)
if (t&bin[i]){
x=fa[x][i];
}
for (int i=;i>=;i--)
if (fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
if (x==y) return x;
else return fa[x][];
}
int main(){
bin[]=;
for (int i=;i<;i++) bin[i]=bin[i-]*;
scanf("%d%d",&n,&m);
blo=sqrt(n);
for (int i=;i<=n;i++)
scanf("%d",&col[i]);
for (int i=;i<=n;i++){
scanf("%d%d",&x,&y);
if (x==)
root=y;
else
if (y==)
root=x;
else
add(x,y);
}
dfs(root);
blonum++;
while (top) belong[st[top--]]=blonum;
for (int i=;i<=m;i++){
scanf("%d%d",&q[i].u,&q[i].v);
if (dfn[q[i].u]>dfn[q[i].v]) std::swap(q[i].v,q[i].u);
scanf("%d%d",&q[i].a,&q[i].b);
q[i].id=i;
}
std::sort(q+,q++m,cmp);
int t=lca(q[].u,q[].v);
solve(q[].u,q[].v);
reverse(t);
res[q[].id]=ans;
if (p[q[].a]&&p[q[].b]&&q[].a!=q[].b) res[q[].id]--;
reverse(t);
for (int i=;i<=m;i++){
solve(q[i-].u,q[i].u);
solve(q[i-].v,q[i].v);
t=lca(q[i].u,q[i].v);
reverse(t);
res[q[i].id]=ans;
if (p[q[i].a]&&p[q[i].b]&&q[i].a!=q[i].b) res[q[i].id]--;
reverse(t);
}
for (int i=;i<=m;i++)
printf("%d\n",res[i]);
}
bzoj3052 WC糖果公园
 #include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <vector>
#include <functional>
#include <ctime>
#include <cstdlib>
#include <sstream>
#include <set>
#include <deque>
#define Rep(i, l, r) for (int i = l; i <= r; ++i)
#define Req(i, l, r) for (int i = l; i >= r; --i)
#define N 200005
long long res[N];
long long pre[N],col[N],v[N],w[N],ans;
int belong[N],go[N],tot,first[N],next[N];
int deep[N],bin[],fa[N][],st[N],top,x,y,n,m,c1,c2,dfn[N],ind,blo,blonum;
int pd[N],p[N],qe,ty;
struct op{
int x,y,id,t;
long long pre;
}c[N],b[N];
bool cmp(op a,op b){
if (belong[a.x]==belong[b.x]&&belong[a.y]==belong[b.y]) return a.t<b.t;
else
if (belong[a.x]==belong[b.x]) return belong[a.y]<belong[b.y];
return belong[a.x]<belong[b.x];
}
void insert(int x,int y){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
}
void add(int x,int y){
insert(x,y);
insert(y,x);
}
int dfs(int x){
int size=;
dfn[x]=++ind;
for (int i=;i<=;i++)
if (deep[x]>=bin[i])
fa[x][i]=fa[fa[x][i-]][i-];
else break;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (pur!=fa[x][]){
fa[pur][]=x;
deep[pur]=deep[x]+;
size+=dfs(pur);
if (size>=blo){
blonum++;
for (int j=;j<=size;j++)
belong[st[top--]]=blonum;
size=;
}
}
}
st[++top]=x;
return size+;
}
void reverse(int x){
if (pd[x]){
ans-=w[p[col[x]]]*v[col[x]];
p[col[x]]--;
pd[x]=;
}
else{
pd[x]=;
p[col[x]]++;
ans+=w[p[col[x]]]*v[col[x]];
}
}
void change(int x,int y){
if (pd[x]){
reverse(x);
col[x]=y;
reverse(x);
}
else{
col[x]=y;
}
}
void solve(int x,int y){
while (x!=y){
if (deep[x]>deep[y]) reverse(x),x=fa[x][];
else reverse(y),y=fa[y][];
}
}
int lca(int x,int y){
if (deep[x]<deep[y]) std::swap(x,y);
int t=deep[x]-deep[y];
for (int i=;i>=;i--)
if (t&bin[i])
x=fa[x][i];
for (int i=;i>=;i--)
if (fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
if (x==y) return x;
else return fa[x][];
}
int main(){
//freopen("tx.txt","r",stdin);
bin[]=;
for (int i=;i<=;i++) bin[i]=bin[i-]*;
scanf("%d%d%d",&n,&m,&qe);
blo=pow(n,2.0/)*0.5;
for (int i=;i<=m;i++)
scanf("%lld",&v[i]);
for (int i=;i<=n;i++)
scanf("%lld",&w[i]);
for (int i=;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);
}
for (int i=;i<=n;i++){
scanf("%lld",&col[i]);
pre[i]=col[i];
}
dfs();
//blonum++;
while (top) belong[st[top--]]=blonum;
for (int i=;i<=qe;i++){
scanf("%d",&ty);
if (!ty){
c1++;
scanf("%d%d",&c[c1].x,&c[c1].y);
c[c1].pre=pre[c[c1].x];
pre[c[c1].x]=c[c1].y;
}
else{
c2++;
scanf("%d%d",&b[c2].x,&b[c2].y);
b[c2].t=c1;
if (dfn[b[c2].x]>dfn[b[c2].y]) std::swap(b[c2].x,b[c2].y);
b[c2].id=c2;
}
}
std::sort(b+,b++c2,cmp);
for (int i=;i<=b[].t;i++)
change(c[i].x,c[i].y);
solve(b[].x,b[].y);
int t=lca(b[].x,b[].y);
reverse(t);
res[b[].id]=ans;
reverse(t);
for (int i=;i<=c2;i++){
for (int j=b[i-].t+;j<=b[i].t;j++)
change(c[j].x,c[j].y);
for (int j=b[i-].t;j>b[i].t;j--)
change(c[j].x,c[j].pre);
solve(b[i-].x,b[i].x);
solve(b[i-].y,b[i].y);
int t=lca(b[i].x,b[i].y);
reverse(t);
res[b[i].id]=ans;
reverse(t);
}
for (int i=;i<=c2;i++)
printf("%lld\n",res[i]);
}

树上莫队 wowow的更多相关文章

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

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

  2. 【BZOJ-3757】苹果树 块状树 + 树上莫队

    3757: 苹果树 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1305  Solved: 503[Submit][Status][Discuss] ...

  3. [BZOJ 3052] [wc2013] 糖果公园 【树上莫队】

    题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之 ...

  4. spoj COT2 - Count on a tree II 树上莫队

    题目链接 http://codeforces.com/blog/entry/43230树上莫队从这里学的,  受益匪浅.. #include <iostream> #include < ...

  5. BZOJ 4129: Haruna’s Breakfast [树上莫队 分块]

    传送门 题意: 单点修改,求一条链的mex 分块维护权值,$O(1)$修改$O(S)$求mex...... 带修改树上莫队 #include <iostream> #include < ...

  6. 【WC2013】糖果公园 [树上莫队]

    题意: 一棵树,修改一个点的颜色,询问两点路径上每种颜色的权值$val[c]$*出现次数的权值$cou[w[c]]$的和 sro VFK 树上莫队 按照王室联邦的方法分块,块的大小直径个数有保证,并不 ...

  7. Codeforces 852I Dating 树上莫队

    Dating 随便树上莫队搞一搞就好啦. #include<bits/stdc++.h> #define LL long long #define LD long double #defi ...

  8. 【XSY1642】Another Boring Problem 树上莫队

    题目大意 给你一棵\(n\)个点的树,每个点有一个颜色\(c_i\),每次给你\(x,y,k\),求从\(x\)到\(y\)的路径上出现次数第\(k\)多的颜色的出现次数 \(n,q\leq 1000 ...

  9. SP10707 COT2 - Count on a tree II (树上莫队)

    大概学了下树上莫队, 其实就是在欧拉序上跑莫队, 特判lca即可. #include <iostream> #include <algorithm> #include < ...

随机推荐

  1. http协议使用实例

    #include <stdio.h>#include <windows.h>#include <wininet.h> #define MAXSIZE 1024#pr ...

  2. 基于HTML5 Canvas的饼状图表实现教程

    昨天我们分享了一款基于HTML5的线性图表应用,效果非常不错,可以看在线DEMO或者实现教程.今天我们继续来分享一款基于HTML5的网页图表,它也是利用Canvas绘制的,但是和前面不同的是,这款图表 ...

  3. 算法导论(第三版)Problems2(归并插入排序、数列逆序计算)

    讨论内容不说明,仅提供相应的程序. 2.1:归并插入排序θ(nlgn) void mergeInsertionSort(int a[], int l, int r, int k) { int m; & ...

  4. 【转】被误解的MVC和被神化的MVVM

    被误解的MVC和被神化的MVVM 作者 唐巧 发布于 2015年11月2日 | ArchSummit全球架构师峰会(北京站)2016年12月02-03日举办   被误解的 MVC MVC 的历史 MV ...

  5. zabbix流量汇聚

    "服务器流量汇总"领导提需求,要把几个数据中心的数据汇总起来,于是就google了一下"zabbix流量汇总" 按照其中一篇博客做了出来,博客地址如下. htt ...

  6. [原创+实战+钓鱼]setoolkit+映射

    所需工具:setoolkit,花生壳 (此方法主要针对没有服务器,没有空间的攻击者.有服务器或者空间可以直接上传setoolkit的生成源码到服务器或者空间.) 1.setoolkit克隆一个站点 | ...

  7. 获取布局 ActionBar

    LayoutInflater inflater = getLayoutInflater();View imageLayout = inflater.inflate(R.layout.preferenc ...

  8. hdu5067Harry And Dig Machine(TSP旅行商问题)

    题目链接: huangjing 题意:给出一幅图.图中有一些点,然后从第1个点出发,然后途径全部有石头的点.最后回到原点,然后求最小距离.当初作比赛的时候不知道这就是旅行商经典问题.回来学了一下. 思 ...

  9. 关于ajax网络请求的封装

    // 封装的ajax网络请求函数// obj 是一个对象function AJAX(obj){ //跨域请求        if (obj.dataType == "jsonp") ...

  10. 读取oracle页面或者进程卡住不动(死锁)

    oracle最坑爹的地方:你insert   update  delete之后  或者kill死锁的时候记得一定要提交事务不然就是死锁卡在那里了 记住  kill死锁也是要提交事务的 select * ...