感谢以下文章作者:

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. NYOJ 409 郁闷的C小加(三) (字符串处理)

    题目链接 描述 聪明的你帮助C小加解决了中缀表达式到后缀表达式的转换(详情请参考"郁闷的C小加(一)"),C小加很高兴.但C小加是个爱思考的人,他又想通过这种方法计算一个表达式的值 ...

  2. ecshop代码修改后提交,无法立即生效

    今天帮一朋友部署一网站.成品的ecshop模版站.在搭建好xammp集成环境,导入数据库,修改配置文件后,报了一大堆错. 其中第一个是关于废弃preg_replace中/e这种用法的,因为存在漏洞,一 ...

  3. python碎片记录(三)

    1.不换行输出 for i in range(5):    print(i,end=' ')不换行打印,end表示每打印一个后面跟的字符 2.利用枚举方式打印输出索引与数值 a=[7,8,9]for ...

  4. 浅谈iOS多线程

    浅谈iOS多线程 首先,先看看进程和线程的概念. 图1.1 这一块不难理解,重点点下他们的几个重要区别: 1,地址空间和资源:进程可以申请和拥有系统资源,线程不行.资源进程间相互独立,同一进程的各线程 ...

  5. Nginx服务安全设置和参数调优

    1.添加参数隐藏Nginx版本号 vim /application/nginx/conf/nginx.conf #http标签下添加 server_tokens off; #测试 [root@cobb ...

  6. HBase原理解析(转)

    本文属于转载,原文链接:http://www.aboutyun.com/thread-7199-1-1.html   前提是大家至少了解HBase的基本需求和组件. 从大家最熟悉的客户端发起请求开始讲 ...

  7. ubuntu查看mysql版本的几种方法

    ubuntu查看mysql版本的几种方法 mysql 1:在终端下:mysql -V(大写) //代码 $ mysql -V mysql Ver 14.14 Distrib 5.5.46, for d ...

  8. 20180830 安装git时报错,

    安装:https://blog.csdn.net/u013256816/article/details/54743470 解决问题:https://blog.csdn.net/daojibruce/a ...

  9. [ python ] 面向对象 - 选课系统

    根据源程序进行改写:    原程序地址:http://www.cnblogs.com/lianzhilei/p/5985333.html  如有侵权立即删除.    感谢原作者将完整的代码提供参考.  ...

  10. 查看压缩包内容tar -tf

    linux 压缩文件内容查看 分类:Linux | 标签: linux  压缩文件内容查看  2012-03-14 22:01阅读(1243)评论(0) 1. zipinfo    执行zipinfo ...