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

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

思路:树链剖分,单点修改,区间查询和与最大值。

 var t1,t2,next,vet,head,dep,flag,tid,fa,top,size,id,son,a
:array[..]of longint;
n,m,i,j,k,k1,t,x,y,tot,time,q,len,f:longint;
ch:string; procedure add(a,b:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
head[a]:=tot;
end; function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end; procedure dfs1(u,fath,depth:longint);
var e,v,maxsize:longint;
begin
flag[u]:=; dep[u]:=depth; fa[u]:=fath;
e:=head[u];
flag[u]:=; size[u]:=;
maxsize:=; son[u]:=;
while e<> do
begin
v:=vet[e];
if flag[v]= then
begin
// h[e]:=;
dfs1(v,u,depth+);
size[u]:=size[u]+size[v];
if size[v]>maxsize then
begin
maxsize:=size[v];
son[u]:=v;
end;
end;
e:=next[e];
end;
end; procedure dfs2(u,ance:longint);
var e,v:longint;
begin
flag[u]:=; inc(time); tid[u]:=time; id[time]:=u; top[u]:=ance;
if son[u]> then dfs2(son[u],ance);
e:=head[u];
while e<> do
begin
v:=vet[e];
if flag[v]= then dfs2(v,v);
e:=next[e];
end;
end; procedure build(l,r,p:longint);
var mid:longint;
begin
if l=r then
begin
t1[p]:=a[id[l]];
t2[p]:=a[id[l]];
exit;
end;
mid:=(l+r)>>;
build(l,mid,p<<);
build(mid+,r,p<<+);
t1[p]:=max(t1[p<<],t1[p<<+]);
t2[p]:=t2[p<<]+t2[p<<+];
end; procedure update(l,r,x,v,p:longint);
var mid:longint;
begin
if l=r then
begin
t1[p]:=v; t2[p]:=v;
exit;
end;
mid:=(l+r)>>;
if x<=mid then update(l,mid,x,v,p<<);
if x>mid then update(mid+,r,x,v,p<<+);
t1[p]:=max(t1[p<<],t1[p<<+]);
t2[p]:=t2[p<<]+t2[p<<+];
end; function querymax(l,r,x,y,p:longint):longint;
var mid,t:longint;
begin
if (l=x)and(r=y) then exit(t1[p]);
mid:=(l+r)>>;
t:=-maxlongint;
if y<=mid then t:=querymax(l,mid,x,y,p<<)
else if x>mid then t:=querymax(mid+,r,x,y,p<<+)
else t:=max(querymax(l,mid,x,mid,p<<),querymax(mid+,r,mid+,y,p<<+));
exit(t);
end; function querysum(l,r,x,y,p:longint):longint;
var mid,t:longint;
begin
if (l=x)and(r=y) then exit(t2[p]);
mid:=(l+r)>>;
t:=;
if y<=mid then t:=querysum(l,mid,x,y,p<<)
else if x>mid then t:=querysum(mid+,r,x,y,p<<+)
else t:=querysum(l,mid,x,mid,p<<)+querysum(mid+,r,mid+,y,p<<+);
exit(t);
end; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; function askmax(x,y:longint):longint;
var f1,f2,t:longint;
begin
t:=-maxlongint;
f1:=top[x]; f2:=top[y];
while f1<>f2 do
begin
if dep[f1]<dep[f2] then
begin
swap(f1,f2); swap(x,y);
end;
t:=max(t,querymax(,n,tid[f1],tid[x],));
x:=fa[f1]; f1:=top[x];
end;
if dep[x]>dep[y] then swap(x,y);
t:=max(t,querymax(,n,tid[x],tid[y],));
exit(t);
end; function asksum(x,y:longint):longint;
var f1,f2,t:longint;
begin
t:=;
f1:=top[x]; f2:=top[y];
while f1<>f2 do
begin
if dep[f1]<dep[f2] then
begin
swap(f1,f2); swap(x,y);
end;
t:=t+querysum(,n,tid[f1],tid[x],);
x:=fa[f1]; f1:=top[x];
end;
if dep[x]>dep[y] then swap(x,y);
t:=t+querysum(,n,tid[x],tid[y],);
exit(t);
end; begin
//assign(input,'bzoj1036.in'); reset(input);
//assign(output,'bzoj1036.out'); rewrite(output);
readln(n);
for i:= to n- do
begin
readln(x,y);
add(x,y);
add(y,x);
end;
for i:= to n do read(a[i]);
dfs1(,-,);
fillchar(flag,sizeof(flag),);
dfs2(,);
fillchar(t1,sizeof(t1),$8f);
build(,n,);
readln(q);
for i:= to q do
begin
readln(ch);
x:=; y:=;
for j:= to length(ch) do
if ch[j]=' ' then break;
while ch[j]=' ' do inc(j);
f:=;
while ch[j]<>' ' do
begin
// if ch[j]='-' then f:=-;
if (ch[j]>='')and(ch[j]<='') then x:=x*+ord(ch[j])-ord('');
inc(j);
end; while ch[j]=' ' do inc(j);
while (j<=length(ch))and(ch[j]<>' ') do
begin
if ch[j]='-' then f:=-;
if (ch[j]>='')and(ch[j]<='') then y:=y*+ord(ch[j])-ord('');
inc(j);
end;
if f=- then y:=-y; if ch[]='C' then update(,n,tid[x],y,);
if (ch[]='Q')and(ch[]='M') then writeln(askmax(x,y));
if (ch[]='Q')and(ch[]='S') then writeln(asksum(x,y));
{ if ch[1]='C' then
begin
delete(ch,1,7);
val(copy(ch,1,pos(' ',ch)-1),x);
val(copy(ch,pos(' ',ch)+1,length(ch)-pos(' ',ch)),y);
update(1,n,tid[x],y,1);
end
else if ch[2]='M' then
begin
delete(ch,1,5);
val(copy(ch,1,pos(' ',ch)-1),x);
val(copy(ch,pos(' ',ch)+1,length(ch)-pos(' ',ch)),y);
writeln(askmax(x,y));
end
else
begin
delete(ch,1,5);
val(copy(ch,1,pos(' ',ch)-1),x);
val(copy(ch,pos(' ',ch)+1,length(ch)-pos(' ',ch)),y);
writeln(asksum(x,y)); end; } end;
//close(input);
//close(output);
end.

这是LCT写法,这种没有结构变化的树上操作还是写树剖吧,BZOJ上LCT只能卡着时限过

 var c:array[..,..]of longint;
mx,sum,w:array[..]of int64;
fa,rev,q,a,b:array[..]of longint;
n,m,i,x,y,k,que,j,f,top,t:longint;
ch:string; procedure update(x:longint);
var l,r:longint;
begin
l:=c[x,]; r:=c[x,];
sum[x]:=sum[l]+sum[r]+w[x];
mx[x]:=w[x];
if mx[l]>mx[x] then mx[x]:=mx[l];
if mx[r]>mx[x] then mx[x]:=mx[r];
//mx[x]:=max(w[x],max(mx[l],mx[r]));
end; function isroot(x:longint):boolean;
begin
if (c[fa[x],]<>x)and(c[fa[x],]<>x) then exit(true);
exit(false);
end; procedure pushdown(x:longint);
var l,r:longint;
begin
l:=c[x,]; r:=c[x,];
if rev[x]= then
begin
rev[x]:=rev[x] xor ; rev[l]:=rev[l] xor ; rev[r]:=rev[r] xor ;
//swap(c[x,],c[x,]);
t:=c[x,]; c[x,]:=c[x,]; c[x,]:=t;
end;
end; procedure rotate(x:longint);
var y,z,l,r:longint;
begin
y:=fa[x]; z:=fa[y];
if c[y,]=x then l:=
else l:=; r:=-l;
if not((c[fa[y],]<>y)and(c[fa[y],]<>y)) then
if c[z,]=y then c[z,]:=x
else c[z,]:=x;
fa[c[x,r]]:=y; fa[y]:=x; fa[x]:=z;
c[y,l]:=c[x,r]; c[x,r]:=y;
update(y);
update(x);
end; procedure splay(x:longint);
var k,y,z,i:longint;
begin
inc(top); q[top]:=x;
k:=x;
while not((c[fa[k],]<>k)and(c[fa[k],]<>k)) do
begin
inc(top); q[top]:=fa[k];
k:=fa[k];
end;
while top> do
begin
pushdown(q[top]);
dec(top);
end; while not((c[fa[x],]<>x)and(c[fa[x],]<>x)) do
begin
y:=fa[x]; z:=fa[y];
if not((c[fa[y],]<>y)and(c[fa[y],]<>y)) then
begin
if (c[y,]=x)xor(c[z,]=y) then rotate(x)
else rotate(y);
end;
rotate(x);
end;
end; procedure access(x:longint);
var t:longint;
begin
t:=;
while x> do
begin
splay(x); c[x,]:=t; update(x);
t:=x; x:=fa[x];
end;
end; procedure makeroot(x:longint);
begin
access(x); splay(x); rev[x]:=rev[x] xor ;
end; procedure link(x,y:longint);
begin
makeroot(x); fa[x]:=y;
end; procedure split(x,y:longint);
begin
makeroot(x); access(y); splay(y);
end; begin
assign(input,'bzoj1036.in'); reset(input);
assign(output,'bzoj1036.out'); rewrite(output);
readln(n);
mx[]:=-maxlongint div ; for i:= to n- do readln(a[i],b[i]);
for i:= to n do
begin
read(w[i]); sum[i]:=w[i]; mx[i]:=w[i];
end;
for i:= to n- do link(a[i],b[i]);
readln(que);
for i:= to que do
begin
readln(ch);
x:=; y:=;
for j:= to length(ch) do
if ch[j]=' ' then break;
while ch[j]=' ' do inc(j);
f:=;
while ch[j]<>' ' do
begin
if (ch[j]>='')and(ch[j]<='') then x:=x*+ord(ch[j])-ord('');
inc(j);
end; while ch[j]=' ' do inc(j);
while (j<=length(ch))and(ch[j]<>' ') do
begin
if ch[j]='-' then f:=-;
if (ch[j]>='')and(ch[j]<='') then y:=y*+ord(ch[j])-ord('');
inc(j);
end;
if f=- then y:=-y; if ch[]='C' then
begin
splay(x);
w[x]:=y;
update(x);
end;
if (ch[]='Q')and(ch[]='M') then
begin
split(x,y);
writeln(mx[y]);
end; if (ch[]='Q')and(ch[]='S') then
begin
split(x,y);
writeln(sum[y]);
end; end;
close(input);
close(output);
end.

UPD(2018.9.19):C++ 树链剖分写法

 #include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
#define fi first
#define se second
#define MP make_pair
#define N 210000
#define MOD 1000000007
#define eps 1e-8
#define pi acos(-1)
#define oo 1e9 int mx[N],sum[N],a[N],head[N],vet[N],nxt[N],top[N],tid[N],id[N],
fa[N],size[N],son[N],dep[N],flag[N],n,cnt,tot;
char ch[]; int read()
{
int v=,f=;
char c=getchar();
while(c<||<c) {if(c=='-') f=-; c=getchar();}
while(<=c&&c<=) v=(v<<)+v+v+c-,c=getchar();
return v*f;
} void add(int a,int b)
{
nxt[++tot]=head[a];
vet[tot]=b;
head[a]=tot;
} void dfs1(int u)
{
flag[u]=; size[u]=;
int maxsize=; son[u]=;
int e=head[u];
while(e)
{
int v=vet[e];
if(!flag[v])
{
fa[v]=u;
dep[v]=dep[u]+;
dfs1(v);
size[u]+=size[v];
if(size[v]>maxsize)
{
maxsize=size[v];
son[u]=v;
}
}
e=nxt[e];
}
} void dfs2(int u,int ance)
{
flag[u]=;
tid[u]=++cnt; id[cnt]=u; top[u]=ance;
if(son[u]) dfs2(son[u],ance);
int e=head[u];
while(e)
{
int v=vet[e];
if(!flag[v]) dfs2(v,v);
e=nxt[e];
}
} void pushup(int p)
{
mx[p]=max(mx[p<<],mx[p<<|]);
sum[p]=sum[p<<]+sum[p<<|];
} void build(int l,int r,int p)
{
if(l==r)
{
mx[p]=sum[p]=a[id[l]];
return;
}
int mid=(l+r)>>;
build(l,mid,p<<);
build(mid+,r,p<<|);
pushup(p);
} void update(int l,int r,int x,int v,int p)
{
if(l==r)
{
mx[p]=sum[p]=v;
return;
}
int mid=(l+r)>>;
if(x<=mid) update(l,mid,x,v,p<<);
else update(mid+,r,x,v,p<<|);
pushup(p);
} int querymax(int l,int r,int x,int y,int p)
{
if(x<=l&&r<=y) return mx[p];
int mid=(l+r)>>;
int ans=-oo;
if(x<=mid) ans=max(ans,querymax(l,mid,x,y,p<<));
if(y>mid) ans=max(ans,querymax(mid+,r,x,y,p<<|));
return ans;
} int querysum(int l,int r,int x,int y,int p)
{
if(x<=l&&r<=y) return sum[p];
int mid=(l+r)>>;
int ans=;
if(x<=mid) ans+=querysum(l,mid,x,y,p<<);
if(y>mid) ans+=querysum(mid+,r,x,y,p<<|);
return ans;
} int qmax(int x,int y)
{
int ans=-oo;
int f1=top[x];
int f2=top[y];
while(f1!=f2)
{
if(dep[f1]<dep[f2])
{
swap(f1,f2);
swap(x,y);
}
ans=max(ans,querymax(,n,tid[f1],tid[x],));
x=fa[f1];
f1=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
ans=max(ans,querymax(,n,tid[x],tid[y],));
return ans;
} int qsum(int x,int y)
{
int ans=;
int f1=top[x];
int f2=top[y];
while(f1!=f2)
{
if(dep[f1]<dep[f2])
{
swap(f1,f2);
swap(x,y);
}
ans+=querysum(,n,tid[f1],tid[x],);
x=fa[f1];
f1=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=querysum(,n,tid[x],tid[y],);
return ans;
} int main()
{
freopen("bzoj1036.in","r",stdin);
freopen("bzoj1036.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n-;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=;i<=n;i++) scanf("%d",&a[i]); cnt=;
dfs1();
memset(flag,,sizeof(flag));
dfs2(,);
for(int i=;i<=N-;i++) mx[i]=-oo;
build(,n,);
int q;
scanf("%d",&q);
//q=0;
for(int i=;i<=q;i++)
{
int x,y;
scanf("%s%d%d",ch,&x,&y);
if(ch[]=='C') update(,n,tid[x],y,);
if(ch[]=='M')
{
int ans=qmax(x,y);
printf("%d\n",ans);
}
if(ch[]=='S')
{
int ans=qsum(x,y);
printf("%d\n",ans);
}
}
}

UPD(2018.9.20):C++ LCT写法

 #include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
#define fi first
#define se second
#define MP make_pair
#define N 210000
#define MOD 1000000007
#define eps 1e-8
#define pi acos(-1)
#define oo 1e9 char ch[];
int t[N][],fa[N],a[N],b[N],q[N],rev[N],n,top;
ll w[N],sum[N],mx[N]; int read()
{
int v=,f=;
char c=getchar();
while(c<||<c) {if(c=='-') f=-; c=getchar();}
while(<=c&&c<=) v=(v<<)+v+v+c-,c=getchar();
return v*f;
} bool isroot(int x)
{
return t[fa[x]][]!=x&&t[fa[x]][]!=x;
} void pushup(int x)
{
int l=t[x][];
int r=t[x][];
sum[x]=sum[l]+sum[r]+w[x];
mx[x]=max(w[x],max(mx[l],mx[r]));
} void pushdown(int x)
{
int l=t[x][];
int r=t[x][];
if(rev[x])
{
rev[x]^=;
rev[l]^=;
rev[r]^=;
swap(t[x][],t[x][]);
}
} void rotate(int x)
{
int y=fa[x];
int z=fa[y];
int l=(t[y][]==x);
int r=l^;
if(!isroot(y)) t[z][t[z][]==y]=x;
fa[t[x][r]]=y; fa[y]=x; fa[x]=z;
t[y][l]=t[x][r]; t[x][r]=y;
pushup(y);
pushup(x);
} void splay(int x)
{
q[++top]=x;
for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
while(top) pushdown(q[top--]);
while(!isroot(x))
{
int y=fa[x];
int z=fa[y];
if(!isroot(y))
{
if(t[y][]==x^t[z][]==y) rotate(x);
else rotate(y);
}
rotate(x);
}
} void access(int x)
{
for(int k=;x;k=x,x=fa[x])
{
splay(x);
t[x][]=k;
pushup(x);
}
} void makeroot(int x)
{
access(x);
splay(x);
rev[x]^=;
} void link(int x,int y)
{
makeroot(x);
fa[x]=y;
} void split(int x,int y)
{
makeroot(x);
access(y);
splay(y);
} int main()
{
//freopen("bzoj1036.in","r",stdin);
//freopen("bzoj1036.out","w",stdout);
int n;
scanf("%d",&n);
mx[]=-oo;
for(int i=;i<=n-;i++) scanf("%d%d",&a[i],&b[i]);
for(int i=;i<=n;i++)
{
scanf("%lld",&w[i]);
mx[i]=sum[i]=w[i];
}
for(int i=;i<=n-;i++) link(a[i],b[i]);
int q;
scanf("%d",&q);
for(int i=;i<=q;i++)
{
int x,y;
scanf("%s%d%d",ch,&x,&y);
if(ch[]=='C')
{
splay(x);
w[x]=y;
pushup(x);
}
if(ch[]=='M')
{
split(x,y);
ll ans=mx[y];
printf("%lld\n",ans);
}
if(ch[]=='S')
{
split(x,y);
ll ans=sum[y];
printf("%lld\n",ans);
}
}
}

【BZOJ1036】树的统计Count(树链剖分,LCT)的更多相关文章

  1. 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

    [BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...

  2. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

    [ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...

  3. BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】

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

  4. Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT

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

  5. BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )

    树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...

  6. bzoj 1036: [ZJOI2008]树的统计Count 树链剖分+线段树

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

  7. BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

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

  8. BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)

    [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14968  Solved: 6079[Submit][Stat ...

  9. Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)

    [ZJOI2008]树的统计Count ★★★ 输入文件:bzoj_1036.in 输出文件:bzoj_1036.out 简单对比 时间限制:5 s 内存限制:162 MB [题目描述] 一棵树上有n ...

  10. BZOJ1036 [ZJOI2008]树的统计Count 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1036 题意概括 一个树,每个节点有一个权值.3种操作. 1:修改某一个节点的权值. 2:询问某两个 ...

随机推荐

  1. localStorage对象

    localStorage对象存储的数据没有时间限制,比如:它可以存储到第二天,第三周,半年,或二三年,只要您的电脑没有重新安装系统或更换硬盘,数据仍然会被保留着. 实例: <!DOCTYPE h ...

  2. FTPClient:enterLocalPassiveMode()方法简单说明

    问题:在Java程序中,使用FTPClient下载FTP文件的时候,可以下载到FTP服务器上的文件夹,但是里面的文件没有下载到本地. 分析:这个涉及到FTP在使用的过程中,客户端和服务端连接过程中,端 ...

  3. JS - 生成UUID

    function uuid(len, radix) { var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw ...

  4. AES加密、解密工具类

    AES加密.解密工具类代码如下: package com.util; import java.io.IOException; import java.io.UnsupportedEncodingExc ...

  5. Python头脑风暴4

    IT是全国平均薪资最高的行业,2017年全国最高,人均13点4万每年. 但技术固然好,创业拼的还是世界观下的创意. 蘑菇街,并夕夕,TikTok,头条,哪个不是创意用IT技术的现实化?? 未来,大平台 ...

  6. 20个必不可少的Python库也是基本的第三方库

    个属于我常用工具的Python库,我相信你看完之后也会觉得离不开它们.他们是: Requests.Kenneth Reitz写的最富盛名的http库.每个Python程序员都应该有它. Scrapy. ...

  7. CF1029C Maximal Intersection

    https://www.luogu.org/problem/show?pid=CF1029C #include<bits/stdc++.h> using namespace std ; # ...

  8. PAT Basic 1080

    1080 MOOC期终成绩 对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,必须首先获得不少于200分的在线编程作业分 ...

  9. matlab图形handle

  10. Freemarker的循环通过assign指令引入计数变量

    这里是一个jeecms框架的前台的一个内容列表集,因为不是每个内容子项符合要求,而且需要统计符合要求的子项个数,仿照java的for循环,需要在循环前声明一个计数变量,这就需要使用Freemaker的 ...