感谢以下文章作者:

http://blog.csdn.net/kuribohg/article/details/41458639

http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

http://blog.csdn.net/jiangyuze831/article/details/41476865

http://hzwer.com/5259.html

做了树上的莫队,感觉对这个算法的思想理解更深了

先分块,不论怎么分,要求同一块中的节点之间的距离不超过O(n0.5)

然后将图的DFS序搞出来

然后将询问(u,v),以u所在的块为第一关键字,以v在dfs序中的位置为第二关键字排序。

然后弄个初始状态,然后就在图上按照询问的顺序“爬”(从(u,v)的状态转移到(u',v'),细节见vfleaking文章)。

至于复杂度,和序列型莫队的分析是一样的,我们的时间开销主要花在“爬”上,我们将爬的开销分成两部分来算:

第一部分:(u,v)中u改变造成的开销,如果在同一块中转移,我们最多需要走O(n0.5)步,要走O(n)次;如果在块间转移,我们最多走O(n)步,要走O(n0.5)次。总的O(n1.5)

第二部分:(u,v)中v改变造成的开销,同一块中的所有点总的开销是O(n)(同一块中的v是按dfs序排的序),有O(n0.5)块,所以是O(n1.5);不同块间走O(n0.5)次,每次O(n),总的也是O(n1.5)

所以总的是O(n1.5)。

这题没说m的范围,开成和n一样要RE,记得开成它的两倍。

 /**************************************************************
Problem: 3757
User: idy002
Language: C++
Result: Accepted
Time:17840 ms
Memory:16640 kb
****************************************************************/ #include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#define P(p) (1<<(p))
#define maxn 100010
#define maxp 15
using namespace std; int n, m;
int root;
vector<int> g[maxn];
int stat[maxn], clr[maxn], cnt[maxn], clr_tot;
int anc[maxn][maxp+], depth[maxn], dfn[maxn], dfs_clock;
int mccno[maxn], mcc_len, mcc_tot;
int ans[maxn]; struct Qu {
int u, v, id;
int a, b;
bool operator<( const Qu & c ) const {
return mccno[u]<mccno[c.u] || ( mccno[u]==mccno[c.u] && dfn[v]<dfn[c.v] );
}
};
Qu qry[maxn]; void dfs( int u, int fa, vector<int> &remain ) {
dfn[u] = ++dfs_clock;
anc[u][] = fa;
for( int p=; p<=maxp; p++ )
anc[u][p] = anc[anc[u][p-]][p-];
depth[u] = depth[fa]+;
vector<int> cur;
for( int t=; t<g[u].size(); t++ ) {
int v = g[u][t];
if( v==fa ) continue;
dfs(v,u,cur);
if( cur.size()>mcc_len ) {
mcc_tot++;
while( !cur.empty() ) {
mccno[ cur.back() ] = mcc_tot;
cur.pop_back();
}
}
}
while( !cur.empty() ) {
remain.push_back( cur.back() );
cur.pop_back();
}
remain.push_back(u);
} int lca( int u, int v ) {
if( depth[u]<depth[v] ) swap(u,v);
int t = depth[u]-depth[v];
for( int p=maxp; p>= && t; p-- )
if( t&(P(p)) ) u = anc[u][p];
if( u==v ) return u;
for( int p=maxp; p>= && anc[u][]!=anc[v][]; p-- )
if( anc[u][p]!=anc[v][p] ) u = anc[u][p], v = anc[v][p];
return anc[u][];
} void inv_sig( int u ) {
int c = clr[u];
int d = stat[u] ? - : ;
stat[u] ^= ;
if( cnt[c]== ) clr_tot++;
cnt[c] += d;
if( cnt[c]== ) clr_tot--;
}
void inverse( int u, int v ) { // inverse T(u,v)
int ca = lca(u,v);
for( ; u!=ca; u=anc[u][] )
inv_sig(u);
for( ; v!=ca; v=anc[v][] )
inv_sig(v);
}
void calc( int q ) {
inverse( qry[q-].u, qry[q].u );
inverse( qry[q-].v, qry[q].v );
int ca = lca( qry[q].u, qry[q].v ); inv_sig( ca );
ans[qry[q].id] = clr_tot;
if( qry[q].a != qry[q].b && cnt[qry[q].a] && cnt[qry[q].b] )
ans[qry[q].id]--;
inv_sig( ca );
} int main() {
scanf( "%d%d", &n, &m );
mcc_len = (int)sqrt(n+);
for( int i=; i<=n; i++ )
scanf( "%d", clr+i );
for( int i=,u,v; i<=n; i++ ) {
scanf( "%d%d", &u, &v );
if( u== ) root=v;
if( v== ) root=u;
if( u&&v ) {
g[u].push_back( v );
g[v].push_back( u );
}
}
for( int i=; i<=m; i++ ) {
scanf( "%d%d%d%d", &qry[i].u, &qry[i].v, &qry[i].a, &qry[i].b );
qry[i].id = i;
} vector<int> remain;
dfs( root, root, remain );
while( remain.size() ) {
mccno[ remain.back() ] = mcc_tot;
remain.pop_back();
} sort( qry+, qry++m ); qry[].u = qry[].v = qry[].u;
for( int i=; i<=m; i++ )
calc(i);
for( int i=; i<=m; i++ )
printf( "%d\n", ans[i] );
}

(代码巨慢,应该是分块时拖下来的)

bzoj 3757 树上莫队的更多相关文章

  1. BZOJ - 3757 树上莫队解决离线路径问题 & 学习心得

    题意:给你一棵树,求u,v最短路径的XXX(本题是统计权值种类) 今天课上摸鱼学了一种有意思的处理路径方式(其实是链式块状树翻车了看别的),据说实际运行跑的比XX记者还快 大概就是像序列莫队那样 首先 ...

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

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

  3. bzoj 3052 树上莫队 待修改

    感谢: http://vfleaking.blog.163.com/blog/static/174807634201311011201627/ http://hzwer.com/5250.html 好 ...

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

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

  5. BZOJ.3052.[WC2013]糖果公园(树上莫队 带修改莫队)

    题目链接 BZOJ 当然哪都能交(都比在BZOJ交好),比如UOJ #58 //67376kb 27280ms //树上莫队+带修改莫队 模板题 #include <cmath> #inc ...

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

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

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

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

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

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

  9. 【BZOJ4129】Haruna’s Breakfast(树上莫队)

    [BZOJ4129]Haruna's Breakfast(树上莫队) 题面 BZOJ Description Haruna每天都会给提督做早餐! 这天她发现早饭的食材被调皮的 Shimakaze放到了 ...

随机推荐

  1. 爬虫--Scrapy之Downloader Middleware

    下载器中间件(Downloader Middleware) 下载器中间件是介于Scrapy的request/response处理的钩子框架. 是用于全局修改Scrapy request和respons ...

  2. 如何将vmworkstation的虚机导成ovf模版

    如何将vmworkstation的虚机导成ovf模版 最近碰见一个事情挺烦的苦恼了我好长一段时间,是这样的公司要进行攻防演练需要搭建一个owaps的靶站练手,环境我在我的电脑上已经搭好了(vmwork ...

  3. C#:Excel上传服务器后导入数据库

  4. 122.Best Time to Buy and Sell Stock II---dp

    题目链接:https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/ 题目大意:基本定义与121类似,不 ...

  5. 62.Unique Paths---dp

    题目链接 题目大意:给一个m*n的方格,从左上角走到右下角,中间无任何障碍,问有多少种走法. 法一:DFS,超时,简单模板深搜,无任何剪枝,结果一半的数据超时.代码如下: public int uni ...

  6. 设置Git远程仓库

    1,注册一个GitHub账户,登陆GitHub账户,添加一个储存库 2,进入Ubuntu命令窗口,创建文件夹.如   mkdir   git echo "# first_git" ...

  7. 【会装】kylin的安装(填坑)和简单使用

     1.简介 kylin的设计思想是空间换时间,将hive上的大表的维度全部排列组合计算也将度量提前计算然后存入HBase库,这个步骤在kylin中称之为build cube. 在查询的时候已经建立cu ...

  8. kvm安装准备

    到实际情况下,做虚拟化是直接做在真机上. 但实验时,可以在虚拟机上进行.(因为做实验的时候没办法连接到桥接模式的网络,所以使用了NAT方式来连接网络) 在vmware安装centos 64bit fo ...

  9. Linux 基础目录和命令

    Linux 标准目录结构   初学Linux,首先需要弄清Linux 标准目录结构 / root --- 启动Linux时使用的一些核心文件.如操作系统内核.引导程序Grub等. home --- 存 ...

  10. POJ 2752 Seek the Name, Seek the Fame(KMP求公共前后缀)

    题目链接:http://poj.org/problem?id=2752 题目大意:给你一串字符串s找到所有的公共前后缀,即既是前缀又是后缀的子串. 解题思路: 如图所示 假设字符串pi与jq为符合条件 ...