zoukankan      html  css  js  c++  java
  • BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

    1036: [ZJOI2008]树的统计Count

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 14982  Solved: 6081
    [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

    ——————————————题解

    毕竟是模板……

    所谓的线段树维护链,就是建很多个线段树,节点一个挨着一个省空间

    代码量……真是……

      1 //大家吼,我要砍树了
      2 #include <iostream>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 #include <queue>
      7 #include <set>
      8 #include <vector>
      9 #include <string.h>
     10 #define siji(i,x,y) for(int i=(x);i<=(y);++i)
     11 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
     12 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
     13 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
     14 #define inf 0x7fffffff
     15 //#define ivorysi
     16 #define mo 97797977
     17 #define hash 974711
     18 #define base 47
     19 #define MAXN 30005
     20 #define fi first
     21 #define se second
     22 #define pii pair<int,int>
     23 using namespace std;
     24 //树的存储
     25 struct node {
     26     int to,next;
     27 }edge[MAXN*3];
     28 int head[MAXN],sumedge,n,q;
     29 int val[MAXN];//点值
     30 
     31 void add(int u,int v) {
     32     edge[++sumedge].to=v;
     33     edge[sumedge].next=head[u];
     34     head[u]=sumedge;
     35 }
     36 //线段树部分变量定义
     37 struct data {
     38     int l,r,//边界
     39         lson,//左儿子(因为不能直接位运算要节省空间)
     40         rson,//右儿子(因为不能直接位运算要节省空间)
     41         sum,//区间总和
     42         maxp,//区间最大值
     43         fa;//单点更新优化
     44     data() {
     45         l=0,r=0,lson=0,rson=0,sum=0,maxp=-inf,fa=0;
     46     }
     47 }tree[MAXN*10];
     48 int treecnt;//树点个数
     49 int w[MAXN];//单点更新优化
     50 
     51 //剖分部分变量定义
     52 int fa[MAXN],//父亲
     53     dep[MAXN],//深度
     54     size[MAXN],//子树大小
     55     son[MAXN],//重儿子
     56     rank[MAXN],//在链中的位置
     57     belong[MAXN],//属于哪条链
     58     top[MAXN],//这个点所在链的深度最小的点
     59     linkcnt,//链数
     60     lroot[MAXN];//每条链的树根
     61 
     62 //剖分部分
     63 void dfs1(int u) {//size,fa,son,dep
     64     size[u]=1;
     65     for(int i=head[u];i;i=edge[i].next) {
     66         int v=edge[i].to;
     67         if(v!=fa[u]) {
     68             fa[v]=u;
     69             dep[v]=dep[u]+1;
     70             dfs1(v);
     71             size[u]+=size[v];
     72             if(size[v]>size[son[u]]) son[u]=v;
     73         }
     74     }
     75 }
     76 void build(int p,int l,int r);
     77 vector<int> line;
     78 void dfs2(int u) {//belong,top,rank
     79     if(!belong[u]) {
     80         belong[u]=++linkcnt;
     81         top[linkcnt]=u;
     82         rank[u]=1;
     83         
     84     }
     85     line.push_back(u);
     86     if(!son[u]) {
     87         lroot[belong[u]]=++treecnt;
     88         build(treecnt,1,line.size());
     89         line.clear();
     90         return;
     91     }
     92     belong[son[u]]=belong[u];
     93     rank[son[u]]=rank[u]+1;
     94     dfs2(son[u]);
     95     for(int i=head[u];i;i=edge[i].next) {
     96         int v=edge[i].to;
     97         if(v!=son[u] && v!=fa[u]) 
     98             dfs2(v);
     99     }
    100     
    101 }
    102 //剖分部分结束
    103 //————————————————————————————
    104 //线段树部分
    105 void build(int p,int l,int r) {
    106     tree[p].l=l;
    107     tree[p].r=r;
    108     if(l==r) {
    109         tree[p].sum=val[line[l-1]];
    110         tree[p].maxp=val[line[l-1]];
    111         w[line[l-1]]=p;
    112         return;
    113     }
    114     int mid=(l+r)>>1;
    115     tree[p].lson=++treecnt;
    116     tree[treecnt].fa=p;
    117     build(treecnt,l,mid);
    118     int t1=tree[tree[p].lson].maxp;
    119     int t3=tree[tree[p].lson].sum;
    120     tree[p].rson=++treecnt;
    121     tree[treecnt].fa=p;
    122     build(treecnt,mid+1,r);
    123     int t2=tree[tree[p].rson].maxp;
    124     int t4=tree[tree[p].rson].sum;
    125     tree[p].sum+=t3+t4;
    126     tree[p].maxp=max(t1,t2);
    127     return;
    128 }
    129 void change(int u) {
    130     tree[w[u]].sum=tree[w[u]].maxp=val[u];
    131     int z=tree[w[u]].fa;
    132     while(z!=0) {
    133         tree[z].sum=tree[tree[z].lson].sum+tree[tree[z].rson].sum;
    134         tree[z].maxp=max(tree[tree[z].lson].maxp,tree[tree[z].rson].maxp);
    135         z=tree[z].fa;
    136     }
    137 }
    138 int treeqsum(int p,int l,int r) {
    139     if(l <= tree[p].l && r >= tree[p].r) {
    140         return tree[p].sum;
    141     }
    142     int mid=(tree[p].l+tree[p].r)>>1;
    143     int t1=0,t2=0;
    144     if(l <= mid) {
    145         t1=treeqsum(tree[p].lson,l,r);
    146     }
    147     if(r > mid){
    148         t2=treeqsum(tree[p].rson,l,r);
    149     }
    150     return t1+t2;
    151 }
    152 int treeqmax(int p,int l,int r) {
    153     if(l <= tree[p].l && r >= tree[p].r) {
    154         return tree[p].maxp;
    155     }
    156     int mid=(tree[p].l+tree[p].r)>>1;
    157     int t1=-inf,t2=-inf;
    158     if(l <= mid) {
    159         t1=treeqmax(tree[p].lson,l,r);
    160     }
    161     if(r > mid){
    162         t2=treeqmax(tree[p].rson,l,r);
    163     }
    164     return max(t1,t2);
    165 }
    166 //线段树部分结束
    167 //——————————————————————————
    168 //解决问题部分
    169 int qsum(int u,int v){
    170     int x=top[belong[u]],y=top[belong[v]],res=0;
    171     while(belong[u]!=belong[v]) {
    172         if(dep[x]>dep[y]){
    173             res+=treeqsum(lroot[belong[x]],tree[lroot[belong[x]]].l,rank[u]);
    174             u=fa[x];
    175         }
    176         else {
    177             res+=treeqsum(lroot[belong[y]],tree[lroot[belong[y]]].l,rank[v]);
    178             v=fa[y];
    179         }
    180         x=top[belong[u]],y=top[belong[v]];
    181     }
    182     x=max(rank[u],rank[v]);
    183     y=rank[u]+rank[v]-x;
    184     res+=treeqsum(lroot[belong[u]],y,x);
    185     return res;
    186 
    187 }
    188 int qmax(int u,int v) {
    189     int x=top[belong[u]],y=top[belong[v]],res=-inf;
    190     while(belong[x]!=belong[y]) {
    191         if(dep[x]>dep[y]){
    192             res=max(res,treeqmax(lroot[belong[x]],tree[lroot[belong[x]]].l,rank[u]));
    193             u=fa[x];
    194         }
    195         else {
    196             res=max(res,treeqmax(lroot[belong[y]],tree[lroot[belong[y]]].l,rank[v]));
    197             v=fa[y];
    198         }
    199         x=top[belong[u]],y=top[belong[v]];
    200     }
    201     x=max(rank[u],rank[v]);
    202     y=rank[u]+rank[v]-x;
    203     res=max(res,treeqmax(lroot[belong[u]],y,x));
    204     return res;
    205 }
    206 void prepare() {
    207     int u,v;
    208     scanf("%d",&n);
    209     xiaosiji(i,1,n) {
    210         scanf("%d %d",&u,&v);
    211         add(u,v),add(v,u);
    212     }
    213     siji(i,1,n) {
    214         scanf("%d",&val[i]);
    215     }
    216     scanf("%d",&q);
    217     dfs1(1),dfs2(1);
    218 }
    219 void solve() {
    220     prepare();
    221     char ord[10];
    222     siji(i,1,q) {
    223         scanf("%s",ord);
    224         if(ord[0]=='C') {
    225             int u;
    226             scanf("%d",&u);
    227             //之前写成scanf("%d%d",&u,&val[u]);应该是因为它获得的是原来的u,可能是个很大的野值
    228             scanf("%d",&val[u]);
    229             change(u);
    230         }
    231         else if(ord[1]=='M') {
    232             int u,v;
    233             scanf("%d%d",&u,&v);
    234             printf("%d
    ",qmax(u,v));
    235         }
    236         else {
    237             int u,v;
    238             scanf("%d%d",&u,&v);
    239             printf("%d
    ",qsum(u,v));
    240         }
    241     }
    242 }
    243 int main(int argc, char const *argv[])
    244 {
    245 #ifdef ivorysi
    246     freopen("f1.in","r",stdin);
    247 #endif
    248     solve();
    249 }
  • 相关阅读:
    Android升级ADT22后会报ClassNotFoundException的原因分析
    修改Android解锁界面
    Android中dip, dp, px,pt, sp之间的区别:
    移动开发:Android官方提供的支持不同屏幕大小的全部方法
    常用正则表达式
    Android多语言与国际化
    Android中的资源与国际化
    Android开发:使用Fragment改造TabActivity
    Android开发–Intent-filter属性详解
    Fragment、Activity比较——Android碎片介绍
  • 原文地址:https://www.cnblogs.com/ivorysi/p/6360287.html
Copyright © 2011-2022 走看看