zoukankan      html  css  js  c++  java
  • [ZJOI2008]树的统计Count 【树链剖分】

    Description

    一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

    Input

    输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

    Output

    对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

    Sample Input

    4
    1 2
    2 3
    4 1
    4 2 1 3
    12
    QMAX 3 4
    QMAX 3 3
    QMAX 3 2
    QMAX 2 3
    QSUM 3 4
    QSUM 2 1
    CHANGE 1 5
    QMAX 3 4
    CHANGE 3 6
    QMAX 3 4
    QMAX 2 4
    QSUM 3 4

    Sample Output

    4
    1
    2
    2
    10
    6
    5
    6
    5
    16

    大致思路:

    一道裸的树链剖分,那么久来总结一下树链剖分的整个过程;

    1. 第一次dfs来确定以下参数:父节点,深度,重链边,size大小
    2. 第二次dfs来确定:新的编号(也就是映射值),指向链的头结点。
    3. 建立一个空的线段树
    4. 遍历一遍点,以点修改的形式把对应的点(也就是之前的映射值)放入线段树,并完成区间信息的合并。
    5. 对于每一个区间询问,都先看这个区间是否属于一条重链上,如果不是,就先利用头结点和父亲节点把区间放置到同一条链上(这个过程是把头结点中深度较深的那个点先放到线段树上,进行信息的统计,直到两个点的头结点相同)
    6. 然后把这两个点放到线段树中去统计信息。这么做的原因是:在一条重链上的点在线段树上是连续并且可维护的,所以可以利用线段树去完成。

    代码:

    这个题目的OJ不知道为什么不能用cin,cout。如果用的话会RE

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int maxn=3e4+7;
      4 const int INF=1<<30;
      5 int weight[maxn],id[maxn],son[maxn],dep[maxn];
      6 int father[maxn],size[maxn],root[maxn];
      7 int idx=0;
      8 struct node{
      9     int l,r;
     10     int maxx,sum;
     11 }tree[maxn<<2];
     12 vector<int> g[maxn];
     13 void dfs(int x,int last,int d)
     14 {
     15     dep[x]=d;
     16     size[x]=1;
     17     father[x]=last;
     18     son[x]=0;
     19     int v;
     20     for(int i=0;i<g[x].size();++i){
     21         v=g[x][i];
     22         if(v==last)
     23             continue;
     24         dfs(v,x,d+1);
     25         if(i==0)
     26             son[x]=v;
     27         else if(size[son[x]]<size[v])
     28             son[x]=v;
     29         size[x]+=size[v];
     30     }
     31 }
     32 void connect(int x,int r)
     33 {
     34     int v;
     35     root[x]=r;
     36     id[x]=++idx;
     37         if(son[x]!=0){
     38         connect(son[x],r);
     39         for(int i=0;i<g[x].size();++i){
     40             v=g[x][i];
     41             if(v!=father[x]&&v!=son[x])
     42                 connect(v,v);
     43         }
     44     }
     45 }
     46 void build(int l,int r,int k)
     47 {
     48     if(l>r)
     49         return ;
     50     tree[k].l=l;
     51     tree[k].r=r;
     52     if(l==r)
     53         return ;
     54     int mid=(l+r)>>1;
     55     build(l,mid,k<<1);
     56     build(mid+1,r,k<<1|1);
     57 }
     58 void change(int tar,int w,int k)
     59 {
     60     int l=tree[k].l;
     61     int r=tree[k].r;
     62     if(l==r){
     63         tree[k].maxx=w;
     64         tree[k].sum=w;
     65         return ;
     66     }
     67     int mid=(l+r)>>1;
     68     if(tar<=mid)
     69         change(tar,w,k<<1);
     70     else
     71         change(tar,w,k<<1|1);
     72     tree[k].maxx=max(tree[k<<1].maxx,tree[k<<1|1].maxx);
     73     tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
     74 }
     75 int query_max(int ql,int qr,int k)
     76 {
     77     int l=tree[k].l;
     78     int r=tree[k].r;
     79     if(ql>r||qr<l)
     80         return -INF;
     81     if(ql<=l&&qr>=r)
     82         return tree[k].maxx;
     83     int mid=(l+r)>>1;
     84     return max(query_max(ql,qr,k<<1),query_max(ql,qr,k<<1|1));
     85 }
     86 int query_sum(int ql,int qr,int k)
     87 {
     88     int l=tree[k].l;
     89     int r=tree[k].r;
     90     if(ql>r||qr<l)
     91         return 0;
     92     if(ql<=l&&qr>=r)
     93         return tree[k].sum;
     94     int mid=(l+r)>>1;
     95     return query_sum(ql,qr,k<<1)+query_sum(ql,qr,k<<1|1);
     96 }
     97 int Cal_Sum(int qa,int qb)
     98 {
     99     int sum=0;
    100     while(root[qa]!=root[qb])
    101     {
    102         if(dep[root[qa]]<dep[root[qb]])
    103             swap(qa,qb);
    104         sum+=query_sum(id[root[qa]],id[qa],1);
    105         qa=father[root[qa]];
    106 
    107     }
    108     if(id[qa]>id[qb])
    109         swap(qa,qb);
    110     sum+=query_sum(id[qa],id[qb],1);
    111     return sum;
    112 }
    113 int Cal_Max(int qa,int qb)
    114 {
    115     int maxx=-INF;
    116     while(root[qa]!=root[qb])
    117     {
    118         if(dep[root[qa]]<dep[root[qb]])
    119             swap(qa,qb);
    120         maxx=max(maxx,query_max(id[root[qa]],id[qa],1));
    121         qa=father[root[qa]];
    122     }
    123     if(id[qa]>id[qb])
    124         swap(qa,qb);
    125     maxx=max(maxx,query_max(id[qa],id[qb],1));
    126     return maxx;
    127 }
    128 int main()
    129 {
    130     //freopen("in.txt","r",stdin);
    131     int n,v,u,q;
    132     char cmd[10];
    133     scanf("%d",&n);
    134     for(int i=1;i<n;++i){
    135         scanf("%d%d",&u,&v);
    136         g[u].push_back(v);
    137         g[v].push_back(u);
    138     }
    139 
    140     for(int i=1;i<=n;++i)
    141         scanf("%d",&weight[i]);
    142     dfs(1,1,1);
    143     connect(1,1);
    144     build(1,n,1);
    145     for(int i=1;i<=n;++i)
    146         change(id[i],weight[i],1);
    147     scanf("%d",&q);
    148     for(int i=0;i<q;++i){
    149         scanf("%s%d%d",cmd,&u,&v);
    150         if(cmd[0]=='C')
    151             change(id[u],v,1);
    152         else if(cmd[1]=='S')
    153             printf("%d
    ",Cal_Sum(u,v));
    154         else
    155             printf("%d
    ",Cal_Max(u,v));
    156     }
    157     return 0;
    158 }
  • 相关阅读:
    寻找 身边的幸福
    XML指南——XML 确认
    你最隐秘的性格在哪?
    不用邀请也可以申请GMail的方法
    XMLDOM对象方法:Document对象方法
    XPath函数
    XML指南——微软的XML解析器
    简/繁体互相转换
    WEB程序开发常用小工具包
    职业规划之电脑程序员的蘑菇定律
  • 原文地址:https://www.cnblogs.com/SCaryon/p/7381550.html
Copyright © 2011-2022 走看看