zoukankan      html  css  js  c++  java
  • 【BZOJ1036】树的统计

    1036: [ZJOI2008]树的统计Count

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 18285  Solved: 7445
    [Submit][Status][Discuss]

    Description

      一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
    一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
    II. 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
     
    题解:树链剖分模板题,不解释啦。
    树链剖分详见大佬们的博客,介绍得很详细
    http://hzwer.com/2543.html
    http://www.cnblogs.com/ghostfly233/p/7168324.html
    代码如下:
      1 #include<cstdio>
      2 #include<iostream>
      3 #include<vector>
      4 #define Max 30005
      5 #define INF 0x7fffffff
      6 using namespace std;
      7 int n,m,cnt,v[Max],dep[Max],size[Max],fa[Max];
      8 int pos[Max],center[Max];//pos:节点标号 center:节点所在重链链头 
      9 vector<int> G[Max];
     10 struct node{int l,r,sum,maxn;}tree[3*Max];
     11 void init(){
     12     scanf("%d",&n);
     13     for(int i=1;i<n;i++){
     14         int x,y; scanf("%d%d",&x,&y);
     15         G[x].push_back(y); G[y].push_back(x);
     16     }
     17     for(int i=1;i<=n;i++) scanf("%d",&v[i]);
     18 }
     19 void dfs1(int x){//求出size、dep、fa 
     20     size[x]=1;
     21     for(int i=0;i<G[x].size();i++){
     22         int to=G[x][i];
     23         if(to==fa[x]) continue;
     24         dep[to]=dep[x]+1; fa[to]=x; dfs1(to);
     25         size[x]+=size[to];
     26     }
     27 }
     28 void dfs2(int x,int chain){//求出pos、center 
     29     int k=0;
     30     pos[x]=++cnt; center[x]=chain;
     31     for(int i=0;i<G[x].size();i++){
     32         int to=G[x][i];
     33         if(dep[to]>dep[x]&&size[to]>size[k]) k=to;//找出重儿子 
     34     }
     35     if(k==0) return;
     36     dfs2(k,chain);//重儿子继承重链 
     37     for(int i=0;i<G[x].size();i++){
     38         int to=G[x][i];
     39         if(dep[to]>dep[x]&&k!=to) dfs2(to,to);//其余儿子分别重新开链 
     40     }
     41 }
     42 void build(int k,int l,int r){//建线段树 
     43     tree[k].l=l; tree[k].r=r;
     44     if(l==r) return;
     45     int mid=(l+r)>>1;
     46     build(k<<1,l,mid); build(k<<1|1,mid+1,r);
     47 }
     48 void change(int k,int x,int add){//单点修改 
     49     int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
     50     if(l==r){tree[k].sum=tree[k].maxn=add; return;}
     51     if(x<=mid) change(k<<1,x,add);
     52     else change(k<<1|1,x,add);
     53     tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
     54     tree[k].maxn=max(tree[k<<1].maxn,tree[k<<1|1].maxn);
     55 }
     56 int querymaxn(int k,int x,int y){
     57     int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
     58     if(l==x&&r==y) return tree[k].maxn;
     59     if(y<=mid) return querymaxn(k<<1,x,y);
     60     else if(x>mid) return querymaxn(k<<1|1,x,y);
     61     else return max(querymaxn(k<<1,x,mid),querymaxn(k<<1|1,mid+1,y));
     62 }
     63 int querysum(int k,int x,int y){
     64     int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
     65     if(l==x&&r==y) return tree[k].sum;
     66     if(y<=mid) return querysum(k<<1,x,y);
     67     else if(x>mid) return querysum(k<<1|1,x,y);
     68     else return querysum(k<<1,x,mid)+querysum(k<<1|1,mid+1,y);
     69 }
     70 int solvemaxn(int x,int y){
     71     int ret=-INF;
     72     while(center[x]!=center[y]){//不在同一重链 
     73         if(dep[center[x]]<dep[center[y]]) swap(x,y);
     74         ret=max(ret,querymaxn(1,pos[center[x]],pos[x]));
     75         x=fa[center[x]];//较深节点向上走到fa[链头] ,并查询这段的maxn 
     76     }
     77     if(pos[x]>pos[y]) swap(x,y);//走到同一重链后还要在查询两点间这一段 
     78     ret=max(ret,querymaxn(1,pos[x],pos[y]));
     79     return ret;
     80 }
     81 int solvesum(int x,int y){
     82     int ret=0;
     83     while(center[x]!=center[y]){
     84         if(dep[center[x]]<dep[center[y]]) swap(x,y);
     85         ret+=querysum(1,pos[center[x]],pos[x]);
     86         x=fa[center[x]];
     87     }
     88     if(pos[x]>pos[y]) swap(x,y);
     89     ret+=querysum(1,pos[x],pos[y]);
     90     return ret;
     91 }
     92 void solve(){
     93     build(1,1,n);
     94     for(int i=1;i<=n;i++) change(1,pos[i],v[i]);
     95     scanf("%d",&m);
     96     for(int i=1;i<=m;i++){
     97         int x,y; char ch[10];
     98         scanf("%s%d%d",ch,&x,&y);
     99         if(ch[0]=='C') change(1,pos[x],y);
    100         else if(ch[1]=='M') printf("%d
    ",solvemaxn(x,y));
    101         else printf("%d
    ",solvesum(x,y));
    102     }
    103 }
    104 int main()
    105 {
    106     init();
    107     dfs1(1);
    108     dfs2(1,1);
    109     solve();
    110     return 0;
    111 } 
  • 相关阅读:
    [原]C++ double 小数精度控制
    C++ double 小数精度控制
    从微软小冰看微软运营手段的转型
    Windows下搭建FTP服务器
    C++ 下使用curl 获取ftp文件
    解决MSF更新证书错误
    mimikaz获取明文密码
    metasploit5配置数据库
    Cobalt Strike几种不常见的上线方式
    Powershell
  • 原文地址:https://www.cnblogs.com/Beginner-/p/7466795.html
Copyright © 2011-2022 走看看