• 洛谷P2590 [ZJOI2008]树的统计


    题目:https://www.luogu.org/problemnew/show/2590

    题目描述

    一棵树上有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本身

    输入输出格式

    输入格式:

    输入文件的第一行为一个整数n,表示节点的个数。

    接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。

    接下来一行n个整数,第i个整数wi表示节点i的权值。

    接下来1行,为一个整数q,表示操作的总数。

    接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

    输出格式:

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

    输入输出样例

    输入样例#1: 
    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
    
    输出样例#1: 
    4
    1
    2
    2
    10
    6
    5
    6
    5
    16
    

    说明

    对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

    解析

    这个。。。没有啥可解析的吧。。。。。。

    树剖版题。

    我终于写对了一个树剖啦。。。。。。

    (我还是太菜了)

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<vector>
      7 using namespace std;
      8 const int N=30500;
      9 const int M=70500;
     10 const int inf=233333333;
     11 
     12 vector<int> edge[N];
     13 
     14 int n,m,ra,rb;
     15 int val[N];
     16 int fa[N],tot[N],depth[N];
     17 int top[N],num[N],numx[N],t;
     18 
     19 struct node{
     20     int maxv,sum;
     21 };
     22 node tree[M];
     23 
     24 void addedge(int x,int y){
     25     edge[x].push_back(y);
     26     edge[y].push_back(x);
     27 }
     28 
     29 void dfsa(int x){
     30     depth[x]=depth[fa[x]]+1;
     31     tot[x]=1;
     32     for (int i=0;i<edge[x].size();++i){
     33         int nxt=edge[x][i];
     34         if (nxt!=fa[x]){
     35             fa[nxt]=x;
     36             dfsa(nxt);
     37             tot[x]+=tot[nxt];
     38         }
     39     }
     40 }
     41 
     42 void dfsb(int x){
     43     ++t;
     44     num[x]=t;
     45     numx[t]=x;
     46     if (!top[x]) top[x]=x;
     47     int big=0;
     48     for (int i=0;i<edge[x].size();++i){
     49         int nxt=edge[x][i];
     50         if (nxt!=fa[x]&&tot[nxt]>tot[big])
     51           big=nxt; 
     52     }
     53     if (big){
     54         top[big]=top[x];
     55         dfsb(big);
     56     }
     57     for (int i=0;i<edge[x].size();++i){
     58         int nxt=edge[x][i];
     59         if (nxt!=fa[x]&&nxt!=big)
     60           dfsb(nxt);
     61     }
     62 }
     63 
     64 void maketree(int o,int l,int r){
     65     if (l==r){
     66         tree[o].maxv=val[numx[l]];
     67         tree[o].sum=val[numx[l]];
     68         return;
     69     }
     70     int ls=o<<1;
     71     int rs=ls|1;
     72     int mid=(l+r)>>1;
     73     maketree(ls,l,mid);
     74     maketree(rs,mid+1,r);
     75     tree[o].sum=tree[ls].sum+tree[rs].sum;
     76     tree[o].maxv=max(tree[ls].maxv,tree[rs].maxv);
     77 }
     78 
     79 void change(int o,int l,int r,int a,int v){
     80     if (l==r){
     81         tree[o].maxv=tree[o].sum=v;
     82         return;
     83     }
     84     int mid=(l+r)>>1;
     85     int ls=o<<1;
     86     int rs=ls|1;
     87     if (a<=mid) change(ls,l,mid,a,v);
     88     else change(rs,mid+1,r,a,v);
     89     tree[o].maxv=max(tree[ls].maxv,tree[rs].maxv);
     90     tree[o].sum=tree[ls].sum+tree[rs].sum;
     91 }
     92 
     93 int getsum(int o,int l,int r,int ql,int qr){
     94     if (ql<=l&&qr>=r) return tree[o].sum;
     95     int mid=(l+r)>>1;
     96     int ls=o<<1;
     97     int rs=ls|1;
     98     int ans=0;
     99     if (ql<=mid) ans+=getsum(ls,l,mid,ql,qr);
    100     if (qr>mid) ans+=getsum(rs,mid+1,r,ql,qr);
    101     return ans;
    102 }
    103 int getmax(int o,int l,int r,int ql,int qr){
    104     if (ql<=l&&qr>=r) return tree[o].maxv;
    105     int mid=(l+r)>>1;
    106     int ls=o<<1;
    107     int rs=ls|1;
    108     int ans=-inf;
    109     if (ql<=mid) ans=max(ans,getmax(ls,l,mid,ql,qr));
    110     if (qr>mid) ans=max(ans,getmax(rs,mid+1,r,ql,qr));
    111     return ans;
    112 }
    113 
    114 int findmax(int a,int b){
    115     int res=-inf;
    116     while (top[a]!=top[b]){
    117         if (depth[top[a]]<depth[top[b]]){
    118             swap(a,b);
    119         }
    120         res=max(res,getmax(1,1,n,num[top[a]],num[a]));
    121         a=fa[top[a]];
    122     }
    123     if (depth[a]>depth[b]) swap(a,b); 
    124     res=max(res,getmax(1,1,n,num[a],num[b]));
    125     return res;    
    126 }
    127 int findsum(int a,int b){
    128     int res=0;
    129     while (top[a]!=top[b]){
    130         if (depth[top[a]]<depth[top[b]]){
    131             swap(a,b);
    132         }
    133         res+=getsum(1,1,n,num[top[a]],num[a]);
    134         a=fa[top[a]];
    135     }
    136     if (depth[a]>depth[b]) swap(a,b);
    137     res+=getsum(1,1,n,num[a],num[b]);
    138     return res;    
    139 }
    140 
    141 int main(){
    142     scanf("%d",&n);
    143     for (int i=1;i<n;++i){
    144         scanf("%d%d",&ra,&rb);
    145         addedge(ra,rb);
    146     }
    147     for (int i=1;i<=n;++i)
    148       scanf("%d",&val[i]);
    149     dfsa(1);
    150     dfsb(1);
    151     maketree(1,1,n);
    152     scanf("%d",&m);
    153     char re[10];
    154     while (m--){
    155         scanf("%s%d%d",re,&ra,&rb);
    156         if (re[0]=='C') change(1,1,n,num[ra],rb);
    157         else if (re[1]=='M') printf("%d
    ",findmax(ra,rb));
    158         else printf("%d
    ",findsum(ra,rb));
    159     }
    160     return 0;
    161 }
    View Code
  • 相关阅读:
    [leetCode]剑指 Offer 43. 1~n整数中1出现的次数
    [leetCode]剑指 Offer 42. 连续子数组的最大和
    HDU
    HDU
    HDU
    HDU
    HDU
    HDU
    POJ
    POJ
  • 原文地址:https://www.cnblogs.com/gjc1124646822/p/7828682.html
Copyright © 2020-2023  润新知