码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 3757 树上莫队

时间:2015-02-22 21:55:30      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:

 

感谢以下文章作者:

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,记得开成它的两倍。

技术分享
  1 /**************************************************************
  2     Problem: 3757
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:17840 ms
  7     Memory:16640 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <cmath>
 12 #include <vector>
 13 #include <algorithm>
 14 #define P(p) (1<<(p))
 15 #define maxn 100010
 16 #define maxp 15
 17 using namespace std;
 18  
 19  
 20 int n, m;
 21 int root;
 22 vector<int> g[maxn];
 23 int stat[maxn], clr[maxn], cnt[maxn], clr_tot;
 24 int anc[maxn][maxp+1], depth[maxn], dfn[maxn], dfs_clock;
 25 int mccno[maxn], mcc_len, mcc_tot;
 26 int ans[maxn];
 27  
 28 struct Qu {
 29     int u, v, id;
 30     int a, b;
 31     bool operator<( const Qu & c ) const {
 32         return mccno[u]<mccno[c.u] || ( mccno[u]==mccno[c.u] && dfn[v]<dfn[c.v] );
 33     }
 34 };
 35 Qu qry[maxn];
 36  
 37 void dfs( int u, int fa, vector<int> &remain ) {
 38     dfn[u] = ++dfs_clock;
 39     anc[u][0] = fa;
 40     for( int p=1; p<=maxp; p++ ) 
 41         anc[u][p] = anc[anc[u][p-1]][p-1];
 42     depth[u] = depth[fa]+1;
 43     vector<int> cur;
 44     for( int t=0; t<g[u].size(); t++ ) {
 45         int v = g[u][t];
 46         if( v==fa ) continue;
 47         dfs(v,u,cur);
 48         if( cur.size()>mcc_len ) {
 49             mcc_tot++;
 50             while( !cur.empty() ) {
 51                 mccno[ cur.back() ] = mcc_tot;
 52                 cur.pop_back();
 53             }
 54         }
 55     }
 56     while( !cur.empty() ) {
 57         remain.push_back( cur.back() );
 58         cur.pop_back();
 59     }
 60     remain.push_back(u);
 61 }
 62  
 63 int lca( int u, int v ) {
 64     if( depth[u]<depth[v] ) swap(u,v);
 65     int t = depth[u]-depth[v];
 66     for( int p=maxp; p>=0 && t; p-- ) 
 67         if( t&(P(p)) ) u = anc[u][p];
 68     if( u==v ) return u;
 69     for( int p=maxp; p>=0 && anc[u][0]!=anc[v][0]; p-- ) 
 70         if( anc[u][p]!=anc[v][p] ) u = anc[u][p], v = anc[v][p];
 71     return anc[u][0];
 72 }
 73  
 74 void inv_sig( int u ) {
 75     int c = clr[u];
 76     int d = stat[u] ? -1 : 1;
 77     stat[u] ^= 1;
 78     if( cnt[c]==0 ) clr_tot++;
 79     cnt[c] += d;
 80     if( cnt[c]==0 ) clr_tot--;
 81 }
 82 void inverse( int u, int v ) {  //  inverse T(u,v)
 83     int ca = lca(u,v);
 84     for( ; u!=ca; u=anc[u][0] )
 85         inv_sig(u);
 86     for( ; v!=ca; v=anc[v][0] )
 87         inv_sig(v);
 88 }
 89 void calc( int q ) {
 90     inverse( qry[q-1].u, qry[q].u );
 91     inverse( qry[q-1].v, qry[q].v );
 92     int ca = lca( qry[q].u, qry[q].v );
 93  
 94     inv_sig( ca );
 95     ans[qry[q].id] = clr_tot;
 96     if( qry[q].a != qry[q].b && cnt[qry[q].a] && cnt[qry[q].b]  ) 
 97         ans[qry[q].id]--;
 98     inv_sig( ca );
 99 }
100  
101 int main() {
102     scanf( "%d%d", &n, &m );
103     mcc_len = (int)sqrt(n+1);
104     for( int i=1; i<=n; i++ ) 
105         scanf( "%d", clr+i );
106     for( int i=1,u,v; i<=n; i++ ) {
107         scanf( "%d%d", &u, &v );
108         if( u==0 ) root=v;
109         if( v==0 ) root=u;
110         if( u&&v ) {
111             g[u].push_back( v );
112             g[v].push_back( u );
113         }
114     }
115     for( int i=1; i<=m; i++ ) {
116         scanf( "%d%d%d%d", &qry[i].u, &qry[i].v, &qry[i].a, &qry[i].b );
117         qry[i].id = i;
118     }
119  
120     vector<int> remain;
121     dfs( root, root, remain );
122     while( remain.size() ) {
123         mccno[ remain.back() ] = mcc_tot;
124         remain.pop_back();
125     }
126  
127     sort( qry+1, qry+1+m );
128  
129     qry[0].u = qry[0].v = qry[1].u;
130     for( int i=1; i<=m; i++ )
131         calc(i);
132     for( int i=1; i<=m; i++ )
133         printf( "%d\n", ans[i] );
134 }
View Code

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

bzoj 3757 树上莫队

标签:

原文地址:http://www.cnblogs.com/idy002/p/4297753.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!