zoukankan      html  css  js  c++  java
  • bzoj 1036: [ZJOI2008]树的统计Count

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036

    解:树链剖分基础题

    对于线性表,我们可以通过线段树、树状数组等数据结构成段修改成段查询,如果想要在树上成段修改查询,我们就需要进行树剖

    树剖的大体思路是把树拆成链然后以一定次序放在线性表上,然后利用各种数据结构处理线性表

    比如处理树上两点u、v之间的路径,我们要知道这条路径与之前拆分的哪些链相交,然后查询线性表上相交部分

    那么时间复杂度为=路径与拆分链相交数*数据结构处理每条链时间

    可以有各种拆分链方法,目前最好的一种是轻重链拆分,拆分后保证任意路径穿过拆分链数为log(n)

    树剖学习推荐博客:http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html

    习题推荐:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#overview

      1 /*
      2  * Problem:  
      3  * Author:  SHJWUDP
      4  * Created Time:  2015/6/10 星期三 23:13:56
      5  * File Name: 233.cpp
      6  * State: 
      7  * Memo: 
      8  */
      9 #include <iostream>
     10 #include <cstdio>
     11 #include <cstring>
     12 #include <algorithm>
     13 
     14 using namespace std;
     15 
     16 const int MaxA=3e4+7;
     17 
     18 struct Edge {
     19     int v, nt;
     20     Edge(){}
     21     Edge(int v, int nt):v(v), nt(nt){}
     22 } edges[MaxA<<1];
     23 
     24 int head[MaxA], edgeNum;
     25 
     26 struct SegmentTree {
     27     int n;
     28     int c[MaxA<<2][2]; ///0:sum 1:max
     29     int *val;
     30     int p, v;
     31     int L, R, op;
     32 #define lson l, m, rt<<1
     33 #define rson m+1, r, rt<<1|1
     34     
     35     void pushUp(int rt) {
     36         c[rt][0]=c[rt<<1][0]+c[rt<<1|1][0];
     37         c[rt][1]=max(c[rt<<1][1], c[rt<<1|1][1]);
     38     }
     39 
     40     void doBuild(int l, int r, int rt) {
     41         if(l==r) {
     42             c[rt][0]=c[rt][1]=val[l];
     43         } else {
     44             int m=(l+r)>>1;
     45             doBuild(lson);
     46             doBuild(rson);
     47             pushUp(rt);
     48         }
     49     }
     50 
     51     void build(int n, int* val) {
     52         this->n=n; this->val=val;
     53         doBuild(1, n, 1);
     54     }
     55 
     56     void doUpdate(int l, int r, int rt) {
     57         if(l==r) {
     58             c[rt][0]=c[rt][1]=v;
     59         } else {
     60             int m=(l+r)>>1;
     61             if(p<=m) doUpdate(lson);
     62             else doUpdate(rson);
     63             pushUp(rt);
     64         }
     65     }
     66 
     67     void update(int p, int v) {
     68         this->p=p; this->v=v;
     69         doUpdate(1, n, 1);
     70     }
     71 
     72     int doQuery(int l, int r, int rt) {
     73         if(L<=l && r<=R) {
     74             return c[rt][op];
     75         } else {
     76             int m=(l+r)>>1;
     77             int res=(op==0?0:0x80000000); 
     78             if(L<=m) res=(op==0?res+doQuery(lson):max(res, doQuery(lson)));
     79             if(m<R) res=(op==0?res+doQuery(rson):max(res, doQuery(rson)));
     80             return res;
     81         }
     82     }
     83 
     84     int query(int L, int R, int op) {
     85         this->L=L; this->R=R; this->op=op;
     86         return doQuery(1, n, 1);
     87     }
     88 #undef lson
     89 #undef rson
     90 } st;
     91 
     92 int N;
     93 int oval[MaxA], val[MaxA];    ///oval:树结点编号对应的值
     94                             ///val:线性表编号对应的值
     95 void init() {
     96     edgeNum=0;
     97     memset(head, -1, sizeof(head));
     98 }
     99 void addEdge(int u, int v) {
    100     edges[edgeNum]=Edge(v, head[u]);
    101     head[u]=edgeNum++;
    102 }
    103 namespace LCT {
    104     int fa[MaxA];        ///fa[x]:x的父亲结点
    105     int siz[MaxA];        ///siz[x]:x子树的结点数
    106     int son[MaxA];        ///son[x]:x的重儿子,即siz最大的儿子(有平行的无所谓,随便一个即可
    107     int dep[MaxA];        ///dep[x]:x的结点深度
    108     int top[MaxA];        ///top[x]:x所在重链中dep值最小的结点
    109                         ///重边:结点与重儿子的连边
    110                         ///重链:由重边连成的路径
    111     int w[MaxA];        ///w[x]:x在线性表中的编号
    112     int id;                ///id:生成w数组时用的计数变量
    113 
    114     int dfs1(int u, int d) {
    115         siz[u]=1; dep[u]=d; son[u]=-1;
    116         for(int i=head[u]; ~i; i=edges[i].nt) {
    117             Edge& e=edges[i];
    118             if(e.v==fa[u]) continue;
    119             fa[e.v]=u;
    120             siz[u]+=dfs1(e.v, d+1);
    121             if(son[u]==-1 || siz[son[u]]<siz[e.v]) son[u]=e.v;
    122         }
    123         return siz[u];
    124     }
    125 
    126     void dfs2(int u, int tp) {    
    127         w[u]=++id; top[u]=tp;
    128         if(son[u]!=-1) dfs2(son[u], tp);
    129         for(int i=head[u]; ~i; i=edges[i].nt) {
    130             Edge& e=edges[i];
    131             if(e.v==fa[u] || e.v==son[u]) continue;
    132             dfs2(e.v, e.v);
    133         }
    134     }
    135 
    136     int query(int u, int v, int op) {
    137         int res=(op==0?0:0x80000000);
    138         int f1=top[u], f2=top[v];
    139         while(f1!=f2) {
    140             if(dep[f1]<dep[f2]) { swap(f1, f2); swap(u, v); }
    141             res=(op==0?res+st.query(w[f1], w[u], op):max(res, st.query(w[f1], w[u], op)));
    142             u=fa[f1]; f1=top[u];
    143         }
    144         if(dep[u]>dep[v]) swap(u, v);
    145         res=(op==0?res+st.query(w[u], w[v], op):max(res, st.query(w[u], w[v], op)));
    146         return res;
    147     }
    148 
    149     void update(int p, int v) {
    150         st.update(w[p], v);
    151     }
    152     
    153     void init() {
    154         int root=1;    ///随便指定树根
    155         id=0;
    156         fa[root]=-1;
    157         dfs1(root, 0);
    158         dfs2(root, root);
    159         for(int i=1; i<=N; i++) {
    160             val[w[i]]=oval[i];
    161         }
    162         st.build(N, val);
    163     }
    164 }
    165 int main() {
    166 #ifndef ONLINE_JUDGE
    167     freopen("in", "r", stdin);
    168     //freopen("out", "w", stdout);
    169 #endif
    170     while(~scanf("%d", &N)) {
    171         init();
    172         for(int i=1; i<N; i++) {
    173             int a, b;
    174             scanf("%d%d", &a, &b);
    175             addEdge(a, b);
    176             addEdge(b, a);
    177         }
    178         for(int i=1; i<=N; i++) {
    179             scanf("%d", &oval[i]);
    180         }
    181         LCT::init();
    182         int Q;
    183         scanf("%d", &Q);
    184         while(Q--) {
    185             char op[7];
    186             int a, b;
    187             scanf("%s%d%d", op, &a, &b);
    188             if(op[0]=='C') {
    189                 LCT::update(a, b);
    190             } else {
    191                 if(op[1]=='S') {
    192                     printf("%d
    ", LCT::query(a, b, 0));
    193                 } else printf("%d
    ", LCT::query(a, b, 1));
    194             }
    195         }
    196     }
    197     return 0;
    198 }
    View Code
  • 相关阅读:
    Delphi中多线程同步过程Synchronize的一些说明
    property中的read,write是什么意思?
    如何用delphi读写csv文件
    将DBGrid中的数据导入Excel表格中
    如何获取combobox显示的值
    WaitForSingleObject 的返回值
    关于GetOverlappedResult函数的一些知识
    串口编程:COMSTAT 结构
    windows 官方镜像下载地址
    ffmpeg 命令行改变视频分辨率
  • 原文地址:https://www.cnblogs.com/shjwudp/p/4567885.html
Copyright © 2011-2022 走看看