题意:一棵树上有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. c#中接口、抽象类、继承综合小练习

    namespace Test { class Program { static void Main(string[] args) { //作业:橡皮rubber鸭子.木wood鸭子.真实的鸭子real ...

  2. javaweb基础(3)_tomcat下部署项目

    一.打包JavaWeb应用 在Java中,使用"jar"命令来对将JavaWeb应用打包成一个War包,jar命令的用法如下:

  3. 01_10_SERVLET如何连接Mysql数据库

    01_10_SERVLET如何连接Mysql数据库 1. 实现类 public void doGet(HttpServletRequest request, HttpServletResponse r ...

  4. dSYM文件

    来到新公司后,前段时间就一直在忙,前不久 项目 终于成功发布上线了,最近就在给项目做优化,并排除一些线上软件的 bug,因为项目中使用了友盟统计,所以在友盟给出的错误信息统计中能比较方便的找出客户端异 ...

  5. Docker 容器的网络连接 & 容器互联

    1. Docker 容器网络基础架构 Docker0 ifconfig查看到的 docker0 是linux的虚拟网桥(OSI数据链路层) docker0 地址划分: 172.17.42.1 255. ...

  6. Ubuntu 开机启动不执行

    解决方案: 1.将/etc/rc.local的命令改成更加兼容的模式,将"#!/bin/sh"改为"#!/bin/bash" 2.将/bin/sh重新链接到/b ...

  7. 怎样处理jmeter中文乱码

    jmeter返回 中文乱码: 1.在jmeter的bin目录下,找到jmeter的配置文件,jmeter.properties,然后把 sampleresult.default.encoding=UT ...

  8. python日记整理

    都是自己的学习总结,要是总结的有问题大佬麻烦评价一下我好修改,谢谢 python插件插件+pycharm基本用法+markdown文本编写+jupyter notebook的基本操作汇总 一.计算机基 ...

  9. light oj 1104 Birthday Paradox (概率题)

    Sometimes some mathematical results are hard to believe. One of the common problems is the birthday ...

  10. 启动Chrome浏览器弹出“You are using an unsupported command-line flag –ignore-certificate-errors. Stability and security will suffer”

    采用如下代码: public static void launchChrome() { System.setProperty("webdriver.chrome.driver", ...