题目描述

一棵树上有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 ;
}

luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]的更多相关文章

  1. BZOJ 1036: [ZJOI2008]树的统计Count-树链剖分(点权)(单点更新、路径节点最值、路径求和)模板,超级认真写了注释啊啊啊

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 23015  Solved: 9336[Submit ...

  2. 树的统计Count---树链剖分

    NEFU专项训练十和十一——树链剖分 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t ...

  3. luoguP2590 [ZJOI2008]树的统计(树链剖分)

    luogu P2590 [ZJOI2008]树的统计 题目 #include<iostream> #include<cstdlib> #include<cstdio> ...

  4. BZOJ1036[ZJOI2008]树的统计——树链剖分+线段树

    题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v ...

  5. [ZJOI2008]树的统计——树链剖分

    本题是一个树链剖分裸题,由于比较菜,老是RE,后来发现是因为使用了全局变量. /************************************************************ ...

  6. [luogu P2590 ZJOI2008] 树的统计 (树链剖分)

    题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u ...

  7. 洛谷P2590 [ZJOI2008] 树的统计 [树链剖分]

    题目传送门 树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t ...

  8. BZOJ 1036 树的统计-树链剖分

    [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 12904 Solved: 5191[Submit][Status ...

  9. BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)

    潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...

随机推荐

  1. Django--分页器(paginator)、Django的用户认证、Django的FORM表单

    分页器(paginator) >>> from django.core.paginator import Paginator >>> objects = ['joh ...

  2. delphi 将Dll等生成资源文件

    资源文件一般为扩展名为res的文件,其自带的资源编译工具BRCC32.EXE(位于/Delphi/BIN目录下) 1.编写rc脚本文本用记事本或其它文本编辑器编写一个扩展名为rc的文件,格式分别为在资 ...

  3. Delphi 正则表达式之TPerlRegEx

    官方网站: http://www.regular-expressions.info/delphi.html 直接下载: http://www.regular-expressions.info/down ...

  4. 服务器一般达到多少QPS比较好?

    每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量. 原理:每天80%的访问集中在20%的时间里,这20%时 ...

  5. mysql5.7-my.cnf

    [client] port = socket=/tmp/my3306.sock [mysql] no-auto-rehash [mysqld] #########base############ us ...

  6. rocketmq集群、配置详解和常用命令

    集群原文地址: http://www.cnblogs.com/520playboy/p/6716235.html 常用命令原文地址: http://www.cnblogs.com/gmq-sh/p/6 ...

  7. websocket 文件上传

    <template>   <div class="pad20">     <input id="file" ref="f ...

  8. 【狼】unity3d 安卓播放视频替代视频纹理

    http://www.cnblogs.com/zhanlang96/p/3726684.html 原创,有问题或错误的话希望大家批评指正 导出apk,是不能用电影纹理的,所以我们只能用这个办法 这个 ...

  9. bash arithmatic

    Arithmetic in bash is done with $ and double parentheses: echo "$(($num1+$num2))" Or $ and ...

  10. centos为用户添加sudo功能

    su chmod a+w /etc/sudoers vim /etc/sudoers [找到root ALL=(ALL) ALL这行] 复制出新的一行,并且将root改为daniel(当前用户名) c ...