构建:像线性的莫队那样,依旧是按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. rsyslog 只读取变化的日志

    <pre name="code" class="html">input(type="imfile" File="/us ...

  2. COJ 0244 HDNOIP201404最短路径

    HDNOIP201404最短路径 难度级别: A: 编程语言:不限:运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 a.b.c是3个互不相等的1 ...

  3. JDBC远程从一个MySql数据库中的一张表里面读出数据(这个数据库需要用SSH隧道连接,大约8W条数据),然后分别插入到另一个数据库中的两张表里

    package com.eeepay.lzj.db; import java.sql.Connection; import java.sql.Date; import java.sql.DriverM ...

  4. 2017年开年的第一次比较大的安全事件: MongoDB “赎金事件”,如何看待互联网安全问题

    今天上午(2017年1月7日),我的微信群中同时出现了两个MongoDB被黑掉要赎金的情况,于是在调查过程中,发现了这个事件.这个事件应该是2017年开年的第一次比较大的安全事件吧,发现国内居然没有什 ...

  5. 聚聚科技---PHP开发笔试题及答案

    1. echo(), print(), print_r()的区别? echo是PHP语言结构, print和print_r是函数.语言结构没有返回值,函数可以有返回值(即便没有用)  . print( ...

  6. hibernate jpa 注解 @Temporal(TemporalType.DATE) 格式化时间日期,页面直接得到格式化类型的值

    1.日期: @Temporal(TemporalType.DATE) @Column(name = "applyDate", nullable = false, length = ...

  7. 为什么要使用Nginx?

    这里做了些基准测试表明nginx打败了其它的轻量级的web服务器和代理服务器,同样也赢了相对不是那么轻量级的产品. 有人说这些基准测试是不准确的,因为在这样那样的环境下,做的比较不一致.我倾向同意基准 ...

  8. [React Testing] Redux Reducers

    Sometimes we want to test our Redux reducers to make sure they work as expected. In this lesson we w ...

  9. C# typeof Gettype is as &拆箱 装箱

    有时候,我们不想用值类型的值,就是想用一个引用..Net提供了一个名为装箱(boxing)的机制,它允许根据值类型来创建一个对象,然后使用对这个新对象的一个引用. 首先,回顾两个重要的事实,1.对于引 ...

  10. C#实现测量程序运行时间及cpu使用时间

    private void ShowRunTime() { TimeSpan ts1 = Process.GetCurrentProcess().TotalProcessorTime; Stopwatc ...