bzoj 3757 树上莫队
感谢以下文章作者:
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 树上莫队的更多相关文章
- BZOJ - 3757 树上莫队解决离线路径问题 & 学习心得
题意:给你一棵树,求u,v最短路径的XXX(本题是统计权值种类) 今天课上摸鱼学了一种有意思的处理路径方式(其实是链式块状树翻车了看别的),据说实际运行跑的比XX记者还快 大概就是像序列莫队那样 首先 ...
- BZOJ 3757 苹果树 ——莫队算法
挺好的一道题目,怎么就没有版权了呢?大数据拍过了,精神AC.... 发现几种颜色这性质比较垃圾,不可加,莫队硬上. %了一发popoqqq大神的博客, 看了一波VFK关于糖果公园的博客, 又找了wjm ...
- bzoj 3052 树上莫队 待修改
感谢: http://vfleaking.blog.163.com/blog/static/174807634201311011201627/ http://hzwer.com/5250.html 好 ...
- [BZOJ 3052] [wc2013] 糖果公园 【树上莫队】
题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之 ...
- BZOJ.3052.[WC2013]糖果公园(树上莫队 带修改莫队)
题目链接 BZOJ 当然哪都能交(都比在BZOJ交好),比如UOJ #58 //67376kb 27280ms //树上莫队+带修改莫队 模板题 #include <cmath> #inc ...
- 【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)
2016-05-09 UPD:学习了新的DFS序列分块,然后发现这个东西是战术核导弹?反正比下面的树分块不知道要快到哪里去了 #include<cmath> #include<cst ...
- BZOJ 4129: Haruna’s Breakfast [树上莫队 分块]
传送门 题意: 单点修改,求一条链的mex 分块维护权值,$O(1)$修改$O(S)$求mex...... 带修改树上莫队 #include <iostream> #include < ...
- 【BZOJ-3757】苹果树 块状树 + 树上莫队
3757: 苹果树 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1305 Solved: 503[Submit][Status][Discuss] ...
- 【BZOJ4129】Haruna’s Breakfast(树上莫队)
[BZOJ4129]Haruna's Breakfast(树上莫队) 题面 BZOJ Description Haruna每天都会给提督做早餐! 这天她发现早饭的食材被调皮的 Shimakaze放到了 ...
随机推荐
- C#里面中将字符串转为变量名
public partial class Form1 : Form { string str = "spp"; public string spp = "very goo ...
- Ajax+innerHTML+Dgls=好的用户体验+高性能+高效率
为了引入Dgls,我们从创建Dom节点说起. 用JS创建Dom节点 var div = document.createElement('div'); div.className = 'gdls'; v ...
- 29、最小的K个数
一.题目 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 二.解法 import java.util.ArrayList; ...
- netif_start_queue/netif_wake_queue/netif_stop_queue
在网卡驱动中,内核为发送数据包的流量控制提供了几个主要的函数,用来在驱动程序和内核之间传递流控信息. 主要有4个: 1]netif_start_queue 启动接口传输队列 2]netif_wake ...
- Redis 启动警告解决【转】
[root@centos224]# service redisd start :M Nov :: (it was originally set to ). _._ _.-``__ ''-._ _.-` ...
- popstate实现history路由拦截,监听页面返回事件
1.当活动历史记录条目更改时,将触发popstate事件. 如果被激活的历史记录条目是通过对history.pushState()的调用创建的, 或者受到对history.replaceState() ...
- Retrofit:类型安全的REST客户端for 安卓&Java
Retrofit:类型安全的REST客户端for 安卓&Java 2014年5月5日 星期一 21:11 官网: http://square.github.io/retrofit/ GitH ...
- HDU 4553 约会安排(线段树区间合并+双重标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 题目大意:就是有三种操作: ①DS x,安排一段长度为x的空闲时间跟屌丝一起,输出这段时间的起点 ...
- 关闭windows 7的自动休眠功能
powercfg -h off powercfg -h on https://www.tulaoshi.com/n/20160401/2075397.html powercfg -h on 该文章&l ...
- Python 2 到 Python 3 的变化
1: commands 被 subprocess 所取代:举例 Python2中使用getoutput: >>> import commands >>> print ...