洛谷——P2590 [ZJOI2008]树的统计

https://www.luogu.org/problem/show?pid=2590#sub

题目描述

一棵树上有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 <algorithm>
  2 #include <string>
  3 #include <cstdio>
  4 
  5 using namespace std;
  6 
  7 const int N(30000+15);
  8 int n,u,v,val[N],q;
  9 char op[10];
 10 
 11 int head[N],sumedge;
 12 struct Edge
 13 {
 14     int u,v,next;
 15     Edge(int u=0,int v=0,int next=0):
 16         u(u),v(v),next(next){}
 17 }edge[N<<1];
 18 void ins(int u,int v)
 19 {
 20     edge[++sumedge]=Edge(u,v,head[u]);
 21     head[u]=sumedge;
 22 }
 23 
 24 int cnt,id[N],dfn[N],size[N],son[N],top[N],dad[N],deep[N];
 25 void DFS(int u,int father,int deepth)
 26 {
 27     deep[u]=deepth;
 28     dad[u]=father;
 29     size[u]=1;
 30     son[u]=0;
 31     for(int i=head[u];i;i=edge[i].next)
 32     {
 33         int to=edge[i].v;
 34         if(dad[u]==to) continue;
 35         DFS(to,u,deepth+1);    size[u]+=size[to];
 36         if(!son[u]||size[son[u]]<size[to]) son[u]=to;
 37     }
 38 }
 39 void DFS_(int u,int Top)
 40 {
 41     top[u]=Top;
 42     id[u]=++cnt;
 43     dfn[cnt]=u;
 44     if(son[u]) DFS_(son[u],Top);
 45     for(int i=head[u];i;i=edge[i].next)
 46     {
 47         int to=edge[i].v;
 48         if(to!=dad[u]&&to!=son[u]) DFS_(to,to);
 49     }
 50 }
 51 
 52 struct Tree
 53 {
 54     int l,r,mid,sumval,maxval;
 55 }tree[N<<2];
 56 void Tree_up(int now)
 57 {
 58     tree[now].sumval=tree[now<<1].sumval+tree[now<<1|1].sumval;
 59     tree[now].maxval=max(tree[now<<1].maxval,tree[now<<1|1].maxval);
 60 }
 61 void Tree_build(int now,int l,int r)
 62 {
 63     tree[now].l=l;tree[now].r=r;
 64     if(l==r)
 65     {
 66         tree[now].maxval=val[dfn[l]];
 67         tree[now].sumval=val[dfn[l]];
 68         return ;
 69     }
 70     tree[now].mid=l+r>>1;
 71     Tree_build(now<<1,l,tree[now].mid);
 72     Tree_build(now<<1|1,tree[now].mid+1,r);
 73     Tree_up(now);
 74 }
 75 void Tree_change(int now,int to,int x)
 76 {
 77     if(tree[now].l==tree[now].r)
 78     {
 79         tree[now].maxval=x;
 80         tree[now].sumval=x;
 81         return ;
 82     }
 83     if(tree[now].mid>=to) Tree_change(now<<1,to,x);
 84     else if(tree[now].mid<to) Tree_change(now<<1|1,to,x);
 85     Tree_up(now);
 86 }
 87 int Tree_querymax(int now,int l,int r)
 88 {
 89     if(tree[now].l==l&&tree[now].r==r) return tree[now].maxval;
 90     if(tree[now].mid>=r) return Tree_querymax(now<<1,l,r);
 91     else if(tree[now].mid<l) return Tree_querymax(now<<1|1,l,r);
 92     else return max(Tree_querymax(now<<1,l,tree[now].mid),Tree_querymax(now<<1|1,tree[now].mid+1,r));
 93 }
 94 int Tree_querysum(int now,int l,int r)
 95 {
 96     if(tree[now].l==l&&tree[now].r==r) return tree[now].sumval;
 97     if(tree[now].mid>=r) return Tree_querysum(now<<1,l,r);
 98     else if(tree[now].mid<l) return Tree_querysum(now<<1|1,l,r);
 99     else return Tree_querysum(now<<1,l,tree[now].mid)+Tree_querysum(now<<1|1,tree[now].mid+1,r);
100 }
101 
102 int List_querymax(int x,int y)
103 {
104     int ret=-1e9;
105     for(;top[x]!=top[y];x=dad[top[x]])
106     {
107         if(deep[top[x]]<deep[top[y]]) swap(x,y);
108         ret=max(ret,Tree_querymax(1,id[top[x]],id[x]));
109     }
110     if(id[x]>id[y]) swap(x,y);
111     ret=max(ret,Tree_querymax(1,id[x],id[y]));
112     return ret;
113 }
114 int List_querysum(int x,int y)
115 {
116     int ret=0;
117     for(;top[x]!=top[y];x=dad[top[x]])
118     {
119         if(deep[top[x]]<deep[top[y]]) swap(x,y);
120         ret+=Tree_querysum(1,id[top[x]],id[x]);
121     }
122     if(id[x]>id[y]) swap(x,y);
123     ret+=Tree_querysum(1,id[x],id[y]);
124     return ret;
125 }
126 
127 int main()
128 {
129     scanf("%d",&n);
130     for(int i=1;i<n;i++)
131         scanf("%d%d",&u,&v),ins(u,v),ins(v,u);
132     for(int i=1;i<=n;i++) scanf("%d",val+i);
133     DFS(1,0,1);DFS_(1,1);
134     Tree_build(1,1,n);
135     scanf("%d",&q);
136     for(;q--;)
137     {
138         scanf("%s%d%d",op,&u,&v);
139         if(op[0]=='C') Tree_change(1,id[u],v);
140         else if(op[1]=='M') printf("%d\n",List_querymax(u,v));
141         else printf("%d\n",List_querysum(u,v));
142     }
143     return 0;
144 }

 

转载于:https://www.cnblogs.com/Shy-key/p/7070772.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值