zoukankan      html  css  js  c++  java
  • bzoj 1468

    大概思路:树点分治,重心树中每个重心维护一个总的平衡树,树中保存属于该重心的点到该重心的距离,然后对于去掉该重心后形成的子树分别再保存一份。

    用这种方式实现的话,还可以支持修改与多次查询,每次操作都是O(logn*logn)

    感悟:

    点分治正如一个前辈说的,是“借助”重心的力量,来维护与查询与某点距离相关的问题,我们知道点u到它各个重心的距离关系,各个重心又保存了所有属于它的点的信息,可以证明,一个点至多属于O(logn)个重心,所有重心拥有的点总和为O(nlogn)。

    本质上来说,树的点分治是通过找重心来对树分治,然后建立了一种层次关系(想象一下,找出一棵树的重心,然后在3维空间向上提升,幷让重心向剩下的各块的重心连边,然后再将各块分层,这样就形成了这种层次关系,表现为树结构就是所谓的重心树)。

      1 /**************************************************************
      2     Problem: 1468
      3     User: idy002
      4     Language: C++
      5     Result: Accepted
      6     Time:6536 ms
      7     Memory:54384 kb
      8 ****************************************************************/
      9  
     10 #include <cstdio>
     11 #include <vector>
     12 #include <map>
     13 #define fprintf(...)
     14 #define N 40010
     15 #define S 2000000
     16 using namespace std;
     17  
     18 struct Stat {
     19     int c, d, s;
     20     Stat( int c, int d, int s ):c(c),d(d),s(s){}
     21 };
     22 struct Splay {
     23     static int son[S][2], pre[S], key[S], siz[S], ntot;
     24     int root;
     25     void init() { root=0; }
     26     inline void update( int nd ) {
     27         siz[nd] = siz[son[nd][0]]+siz[son[nd][1]]+1;
     28     }
     29     void rotate( int nd, int d ) {
     30         int p=pre[nd];
     31         int s=son[nd][!d];
     32         int ss=son[s][d];
     33          
     34         son[nd][!d] = ss;
     35         son[s][d] = nd;
     36         if( p ) son[p][ nd==son[p][1] ] = s;
     37         else root = s;
     38  
     39         pre[nd] = s;
     40         pre[s] = p;
     41         if( ss ) pre[ss] = nd;
     42          
     43         update( nd );
     44         update( s );
     45     }
     46     void splay( int nd, int top=0 ) {
     47         while( pre[nd]!=top ) {
     48             int p = pre[nd];
     49             int nl = nd==son[p][0];
     50             if( pre[p]==top ) {
     51                 rotate( p, nl );
     52             } else {
     53                 int pp = pre[p];
     54                 int pl = p==son[pp][0];
     55                 if( nl==pl ) {
     56                     rotate( pp, pl );
     57                     rotate( p, nl );
     58                 } else {
     59                     rotate( p, nl );
     60                     rotate( pp, pl );
     61                 }
     62             }
     63         }
     64     }
     65     int newnode( int p, int k ) {
     66         int nd = ++ntot;
     67         son[nd][0] = son[nd][1] = 0;
     68         pre[nd] = p;
     69         key[nd] = k;
     70         siz[nd] = 1;
     71         return nd;
     72     }
     73     void insert( int k ) {
     74         if( !root ) {
     75             root = newnode( 0, k );
     76             return;
     77         }
     78         int nd = root;
     79         while( son[nd][ k>key[nd] ] ) nd=son[nd][ k>key[nd] ];
     80         son[nd][ k>key[nd] ] = newnode( nd, k );
     81         splay( son[nd][ k>key[nd] ] );
     82     }
     83     int query( int k ) {
     84         int nd=root;
     85         int lnd;
     86         int rt = 0;
     87         while(nd) {
     88             lnd = nd;
     89             if( key[nd]>k ) {
     90                 nd = son[nd][0];
     91             } else {
     92                 rt += siz[son[nd][0]]+1;
     93                 nd = son[nd][1];
     94             }
     95         }
     96         splay( lnd );
     97         return rt;
     98     }
     99 };
    100 int Splay::son[S][2], Splay::pre[S], Splay::key[S], Splay::siz[S], Splay::ntot;
    101  
    102  
    103 int n, qdis;
    104 vector<int> g[N], ww[N];
    105 vector<Stat> st[N];
    106 map<int,Splay > spy[N];
    107 int vis[N], anc[N], siz[N], bac[N], dis[N];
    108 int qu[N], bg, ed;
    109  
    110 void build( int rt ) {
    111     /* find the core of the block containing rt */
    112     qu[bg=ed=1] = rt;
    113     anc[rt] = rt;
    114     siz[rt] = bac[rt] = 0;
    115     while( ed>=bg ) {
    116         int u=qu[bg++];
    117         for( int t=0; t<g[u].size(); t++ ) {
    118             int v=g[u][t];
    119             if( vis[v] || v==anc[u] ) continue;
    120             qu[++ed] = v;
    121             anc[v] = u;
    122             siz[v] = bac[v] = 0;
    123         }
    124     }
    125     for( int i=ed; i>=1; i-- ) {
    126         int u=qu[i];
    127         int p=anc[u];
    128         siz[u]++;
    129         siz[p] += siz[u];
    130         if( bac[p]<siz[u] ) bac[p]=siz[u];
    131     }
    132     for( int i=ed; i>=1; i-- ) {
    133         int u=qu[i];
    134         if( bac[u]<siz[rt]-siz[u] ) bac[u]=siz[rt]-siz[u];
    135     }
    136     for( int i=ed; i>=1; i-- ) {
    137         int u=qu[i];
    138         if( bac[u]<bac[rt] ) rt=u;
    139     }
    140     /* statistics the info of the block */
    141     spy[rt][0].init();
    142     spy[rt][0].insert( 0 );
    143     st[rt].push_back( Stat(rt,0,0) );
    144     vis[rt] = true;
    145     fprintf( stderr, "%d as core
    ", rt );
    146     for( int tm=0; tm<g[rt].size(); tm++ ) {
    147         int r=g[rt][tm], w=ww[rt][tm];
    148         if( vis[r] ) continue;
    149         qu[bg=ed=1] = r;
    150         anc[r] = rt;
    151         dis[r] = w;
    152         while( ed>=bg ) {
    153             int u=qu[bg++];
    154             for( int t=0; t<g[u].size(); t++ ) {
    155                 int v=g[u][t], w=ww[u][t];
    156                 if( vis[v] || v==anc[u] ) continue;
    157                 qu[++ed] = v;
    158                 anc[v] = u;
    159                 dis[v] = dis[u]+w;
    160             }
    161         }
    162         spy[rt][r].init();
    163         for( int i=ed; i>=1; i-- ) {
    164             int u=qu[i];
    165             spy[rt][0].insert( dis[u] );
    166             spy[rt][r].insert( dis[u] );
    167             st[u].push_back( Stat(rt,dis[u],r) );
    168         }
    169         build( r );
    170     }
    171 }
    172  
    173 int main() {
    174     scanf( "%d", &n );
    175     for( int i=1,u,v,w; i<n; i++ ) {
    176         scanf( "%d%d%d", &u, &v, &w );
    177         g[u].push_back( v );
    178         g[v].push_back( u );
    179         ww[u].push_back( w );
    180         ww[v].push_back( w );
    181     }
    182     scanf( "%d", &qdis );
    183     build(1);
    184     for( int u=1; u<=n; u++ ) {
    185         fprintf( stderr, "Stat of %d:
    ", u );
    186         for( int t=0; t<st[u].size(); t++ ) {
    187             fprintf( stderr, "core=%d dis=%d subcore:%d
    ", st[u][t].c, st[u][t].d, st[u][t].s );
    188         }
    189         fprintf( stderr, "
    " );
    190     }
    191      
    192     int ans = 0;
    193     for( int u=1; u<=n; u++ ) {
    194         int tans=0;
    195         for( int t=0; t<st[u].size(); t++ ) {
    196             Stat &s = st[u][t];
    197             tans += spy[s.c][0].query( qdis-s.d )- (s.s?spy[s.c][s.s].query( qdis-s.d ):0);
    198         }
    199         fprintf( stderr, "%d added %d
    ", u, tans-1 );
    200         ans += tans-1;
    201     }
    202     printf( "%d
    ", ans/2 );
    203 }
    View Code
  • 相关阅读:
    用C++实现网络编程---抓取网络数据包的实现方法
    UNICODE字符串与多字节字符串的转换
    MFC ComboBox的使用
    Windows API学习---线程与内核对象的同步
    Windows API学习---用户方式中的线程同步
    MFC读取XML文件并解析
    Windows API学习---插入DLL和挂接API
    常用[js,css,jquery,html]
    JDBC链接MySQL和Oracle
    使用.NET MVC框架项目开发流程(项目开发流程)
  • 原文地址:https://www.cnblogs.com/idy002/p/4369703.html
Copyright © 2011-2022 走看看