zoukankan      html  css  js  c++  java
  • 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,记得开成它的两倍。

      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
    ", ans[i] );
    134 }
    View Code

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

  • 相关阅读:
    前端基础学习分享
    IOS中block和代理
    最近一个项目的反思
    Coreseek Windows下安装调试
    iOS对象属性详解
    我眼里“维多利亚的秘密”中最性感的营销三点式
    用CSS制作带图标的按钮
    简单权限管理设计
    CentOS工作内容(三)配置网络IP地址
    CentOS工作内容(二)关闭SELinux
  • 原文地址:https://www.cnblogs.com/idy002/p/4297753.html
Copyright © 2011-2022 走看看