题目描述

一棵树上有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之间。


这题本身应该是一题树链剖分果题。。QAQ

 //不用lazy-tag真是爽!
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define inf 0x3f3f3f3f
#define ls x<<1
#define rs x<<1|1 int read(){
char ch;
int re=;
bool flag=;
while((ch=getchar())!='-'&&(ch<''||ch>''));
ch=='-'?flag=:re=ch-'';
while((ch=getchar())>=''&&ch<='') re=re*+ch-'';
return flag?-re:re;
} struct Edge{
int to,nxt;
Edge(int to=,int nxt=):
to(to),nxt(nxt){}
}; struct Segment{
int l,r,su,mx;
Segment(){
mx=-inf;
}
}; const int maxn=; int n,m,cnt=,dc=;
int head[maxn],val[maxn];
int top[maxn],dep[maxn],fa[maxn],id[maxn],son[maxn],sz[maxn];
Edge G[maxn<<];
Segment T[maxn<<]; inline void a_ed(int from,int to){
G[++cnt]=Edge(to,head[from]),head[from]=cnt;
G[++cnt]=Edge(from,head[to]),head[to]=cnt;
} inline void push_up(int x){
T[x].mx=max(T[ls].mx,T[rs].mx);
T[x].su=T[ls].su+T[rs].su;
} void build(int x,int l,int r){
T[x].l=l,T[x].r=r;
if(l==r){
T[x].su=T[x].mx=val[l];
return;
}
int mid=l+r>>;
build(ls,l,mid); build(rs,mid+,r);
push_up(x);
} void update(int x,int M,int c){
if(T[x].l==T[x].r){
T[x].su=T[x].mx=c;
return;
}
int mid=T[x].l+T[x].r>>;
if(M<=mid) update(ls,M,c);
else update(rs,M,c);
push_up(x);
} int query(int x,int L,int R,bool kind){
if(L<=T[x].l&&T[x].r<=R)
if(kind) return T[x].su;
else return T[x].mx;
int mid=T[x].l+T[x].r>>;
if(R<=mid) return query(ls,L,R,kind);
else if(L>mid) return query(rs,L,R,kind);
else{
if(kind) return query(ls,L,mid,kind)+query(rs,mid+,R,kind);
else return max(query(ls,L,mid,kind),query(rs,mid+,R,kind));
}
} void dfs1(int no,int p){
fa[no]=p;
sz[no]=;
dep[no]=dep[p]+;
for(int e=head[no];e;e=G[e].nxt){
int nt=G[e].to;
if(nt!=p){
dfs1(nt,no);
sz[no]+=sz[nt];
if(!son[no]||sz[nt]>sz[son[no]])
son[no]=nt;
}
}
} void dfs2(int no,int p){
if(!son[no]) return;
top[son[no]]=top[no];
id[son[no]]=++dc;
dfs2(son[no],no);
for(int e=head[no];e;e=G[e].nxt){
int nt=G[e].to;
if(nt!=p&&nt!=son[no]){
top[nt]=nt;
id[nt]=++dc;
dfs2(nt,no);
}
}
} int calc(int x,int y,bool kind){
int sum=,f1=top[x],f2=top[y];
if(!kind) sum=-inf;
while(f1!=f2){
if(dep[f1]<dep[f2]){ swap(f1,f2),swap(x,y); }
if(kind)
sum+=query(,id[f1],id[x],kind);
else
sum=max(sum,query(,id[f1],id[x],kind));
x=fa[f1];
f1=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
if(kind) sum+=query(,id[x],id[y],kind);
else sum=max(sum,query(,id[x],id[y],kind));
return sum;
} int main(){
// freopen("temp.in","r",stdin);
n=read();
for(int i=,from,to;i<n;i++){
from=read(); to=read();
a_ed(from,to);
}
dfs1(,);
top[]=;
id[]=;
dfs2(,);
for(int i=;i<=n;i++) val[id[i]]=read();
build(,,n);
m=read();
char opt[];
int x,y;
while(m--){
scanf("%s",opt);
x=read(),y=read();
switch(opt[]){
case 'H':{
update(,id[x],y);
break;
}
case 'M':{
printf("%d\n",calc(x,y,));
break;
}
default:{
printf("%d\n",calc(x,y,));
break;
}
}
}
return ;
}

刚学了LCT的我。。想用LCT过了这一题。。

可是。。T了。。QAQ

顺便终于明白、、把一堆变量包进一个结构体里还不用指针构成的splay还不如拆成一个个数组。。

 #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define rint register int
#define inf 0x3f3f3f3f int read(){
char ch;
int re=;
bool flag=;
while((ch=getchar())!='-'&&(ch<''||ch>''));
ch=='-'?flag=:re=ch-'';
while((ch=getchar())>=''&&ch<='') re=re*+ch-'';
return flag?-re:re;
} struct Edge{
int to,nxt;
Edge(int to=,int nxt=):
to(to),nxt(nxt){}
}; const int maxn=; int n,m,cnt=,top;
//struct 变 数组
int ch[maxn][],su[maxn],mx[maxn],fa[maxn],rev[maxn];
int head[maxn],val[maxn],stk[maxn];
Edge G[maxn<<]; inline void a_ed(int from,int to){
G[++cnt]=Edge(to,head[from]);
head[from]=cnt;
G[++cnt]=Edge(from,head[to]);
head[to]=cnt;
} inline void push_up(int x){
mx[x]=max(mx[ch[x][]],max(mx[ch[x][]],val[x]));
su[x]=su[ch[x][]]+su[ch[x][]]+val[x];
} inline void push_down(int x){
if(rev[x]){
rev[ch[x][]]^=,rev[ch[x][]]^=;
swap(ch[x][],ch[x][]);
rev[x]=;
}
} inline bool isroot(int x){
return ch[fa[x]][]!=x&&ch[fa[x]][]!=x;
} void rot(int x){
int y=fa[x],z=fa[y],l,r;
fa[x]=z;
if(!isroot(y)) ch[z][ch[z][]==y]=x;
if(ch[y][]==x) l=;
else l=;
r=l^;
fa[ch[x][r]]=y;
ch[y][l]=ch[x][r];
fa[y]=x;
ch[x][r]=y;
push_up(y),push_up(x);
} void splay(int x){
top=; stk[top]=x;
for(rint i=x;!isroot(i);i=fa[i]) stk[++top]=fa[i];
for(rint i=top;i;i--) push_down(stk[i]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if((ch[y][]==x)^(ch[z][]==y)) rot(x);
else rot(y);
}
rot(x);
}
} void acc(int x){
int t=;
while(x){
splay(x);
ch[x][]=t;
push_up(x);
t=x; x=fa[x];
}
} void make_root(int x){ acc(x),splay(x),rev[x]^=; } void split(int x,int y){ make_root(x),acc(y),splay(y); } void dfs(int no,int fat){
fa[no]=fat;
for(rint e=head[no];e;e=G[e].nxt)
if(G[e].to!=fat)
dfs(G[e].to,no);
} int main(){
// freopen("temp.in","r",stdin);
n=read();
for(rint i=,from,to;i<n;i++){
from=read(),to=read();
a_ed(from,to);
}
memset(mx,-inf,(n+)<<);
for(rint i=;i<=n;i++){
val[i]=read();
su[i]=mx[i]=val[i];
}
dfs(,);
char opt[]; int x,y;
m=read();
while(m--){
scanf("%s",opt);
x=read(),y=read();
switch(opt[]){
case 'H':{
acc(x);
splay(x);
val[x]=y;
push_up(x);
break;
}
case 'M':{
split(x,y);
printf("%d\n",mx[y]);
break;
}
default:{
split(x,y);
printf("%d\n",su[y]);
break;
}
}
}
return ;
}

最新文章

  1. sh
  2. Ubuntu root 密码 sudo passwd
  3. C#基础--面向对象计算器
  4. hdu5514-Frogs(容斥原理)好题
  5. linux 源码安装软件原理
  6. HDU3368+枚举
  7. android 滚动视图(ScrollView)
  8. 一步一步学c#(四):继承
  9. Effective C++ Item 33 避免遮掩继承过来的名称
  10. jQuery小测的总结
  11. js拼接字符串后swiper不能动的解决方案
  12. shell编程—变量(三)
  13. HDU--1540 Tunnel Warfare(线段树区间更新)
  14. (编辑距离问题 线性DP) nyoj1431-DNA基因鉴定
  15. U3D外包团队:五款IDE推荐!
  16. 基于Linux命令行KVM虚拟机的安装配置与基本使用
  17. C# .NET 根据Url链接保存Image图片到本地磁盘
  18. HDU 2647 Reward(拓扑排序,vector实现邻接表)
  19. bzoj3685 普通veb树
  20. 显示器如何显示一个YUV422格式的图形

热门文章

  1. 给元素绑定 class
  2. shell 提取文件的某行,并在行尾添加字符
  3. 编译php-5.5.15出错,xml2-config not found
  4. 【LeetCode 32】最长有效括号
  5. cent OS 7 下安装 python 3.6
  6. centos安装virtualbox
  7. 2059-authentication plugin &#39;caching_sha2_password&quot;cnnot bt loaded :mysql8.0数据库连接不上(Navicat)
  8. PHP中输出字符串(echo,print,printf,print_r和var_dump)的区别【转载】
  9. CentOS 7.4安装telnet服务端
  10. 时间同步服务器NTP