题目大意:

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

思路:

树链剖分

衣服都不穿的

搞到线段树里,然后维护维护

背一背代码

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
#define MAXN 30101
#define MOD
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,Cnt,nxt[MAXN*],fst[MAXN],to[MAXN*],val[MAXN];
int fa[MAXN],dep[MAXN],bl[MAXN],cnt[MAXN],hsh[MAXN];
struct data{int mx,sum,l,r;}tr[MAXN*];
void add(int u,int v) {nxt[++Cnt]=fst[u],fst[u]=Cnt,to[Cnt]=v;}
void build(int x)
{
for(int i=fst[x];i;i=nxt[i])
{
if(to[i]==fa[x]) continue;
dep[to[i]]=dep[x]+;
fa[to[i]]=x;
build(to[i]);
cnt[x]+=cnt[to[i]];
}
cnt[x]++;
}
void Build(int x,int chn)
{
int hvs=;hsh[x]=++Cnt,bl[x]=chn;
for(int i=fst[x];i;i=nxt[i])
if(fa[x]!=to[i]&&cnt[hvs]<cnt[to[i]]) hvs=to[i];
if(!hvs) return ;
Build(hvs,chn);
for(int i=fst[x];i;i=nxt[i])
if(fa[x]!=to[i]&&hvs!=to[i]) Build(to[i],to[i]);
}
void s_build(int k,int l,int r)
{
tr[k].l=l,tr[k].r=r;
if(l==r) return ;
int mid=(l+r)>>;
s_build(k<<,l,mid);
s_build(k<<|,mid+,r);
}
void upd(int k,int pos,int x)
{;
int l=tr[k].l,r=tr[k].r;
if(l==r) {tr[k].mx=tr[k].sum=x;return ;}
int mid=(l+r)>>;
if(mid>=pos) upd(k<<,pos,x);
else upd(k<<|,pos,x);
tr[k].mx=max(tr[k<<].mx,tr[k<<|].mx);
tr[k].sum=tr[k<<].sum+tr[k<<|].sum;
}
int q_sum(int k,int a,int b)
{
int l=tr[k].l,r=tr[k].r;
if(l==a&&r==b) return tr[k].sum;
int mid=(l+r)>>;
if(b<=mid) return q_sum(k<<,a,b);
if(a>mid) return q_sum(k<<|,a,b);
else return q_sum(k<<,a,mid)+q_sum(k<<|,mid+,b);
}
int q_mx(int k,int a,int b)
{
int l=tr[k].l,r=tr[k].r;
if(l==a&&r==b) return tr[k].mx;
int mid=(l+r)>>;
if(b<=mid) return q_mx(k<<,a,b);
if(a>mid) return q_mx(k<<|,a,b);
else return max(q_mx(k<<,a,mid),q_mx(k<<|,mid+,b));
}
int main()
{
n=read();int a,b,res;
for(int i=;i<n;i++) {a=read(),b=read();add(a,b);add(b,a);}
for(int i=;i<=n;i++) val[i]=read();fa[]=;
build();Cnt=;
Build(,);
s_build(,,n);
for(int i=;i<=n;i++) upd(,hsh[i],val[i]);
int T=read();
char ch[];
while(T--)
{
scanf("%s",ch);a=read(),b=read();
if(ch[]=='C') {val[a]=b;upd(,hsh[a],b);}
else if(ch[]=='M')
{
res=-inf;
while(bl[a]!=bl[b])
{
if(dep[bl[a]]<dep[bl[b]]) swap(a,b);
res=max(res,q_mx(,hsh[bl[a]],hsh[a]));
a=fa[bl[a]];
}
res=max(res,q_mx(,min(hsh[a],hsh[b]),max(hsh[a],hsh[b])));
printf("%d\n",res);
}
else if(ch[]=='S')
{
res=;
while(bl[a]!=bl[b])
{
if(dep[bl[a]]<dep[bl[b]]) swap(a,b);
res+=q_sum(,hsh[bl[a]],hsh[a]);
a=fa[bl[a]];
}
res+=q_sum(,min(hsh[a],hsh[b]),max(hsh[a],hsh[b]));
printf("%d\n",res);
}
}
}

UPD 2018.9.19

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#define ll long long
#define inf 2147383611
#define MAXN 500100
using namespace std;
inline int read()
{
int x=,f=;
char ch;ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,cnt,nxt[MAXN<<],fst[MAXN],to[MAXN<<],val[MAXN];
int fa[MAXN],dep[MAXN],bl[MAXN],sz[MAXN],hsh[MAXN],mx[MAXN<<],sum[MAXN<<];
void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
void dfs(int x)
{
sz[x]=,dep[x]=dep[fa[x]]+;
for(int i=fst[x];i;i=nxt[i])
if(to[i]!=fa[x]) {fa[to[i]]=x;dfs(to[i]);sz[x]+=sz[to[i]];}
}
void Dfs(int x,int anc)
{
hsh[x]=++cnt,bl[x]=anc;int hvs=;
for(int i=fst[x];i;i=nxt[i])
if(dep[to[i]]>dep[x]&&sz[hvs]<sz[to[i]]) hvs=to[i];
if(!hvs) return ;Dfs(hvs,anc);
for(int i=fst[x];i;i=nxt[i])
if(dep[to[i]]>dep[x]&&to[i]!=hvs) {Dfs(to[i],to[i]);}
}
void mdf(int k,int l,int r,int x,int w)
{
if(l==r) {mx[k]=sum[k]=w;return ;}
int mid=(l+r)>>;
if(x<=mid) mdf(k<<,l,mid,x,w);
else mdf(k<<|,mid+,r,x,w);
mx[k]=max(mx[k<<],mx[k<<|]),sum[k]=sum[k<<]+sum[k<<|];
}
int querys(int k,int l,int r,int a,int b)
{
if(l==a&&r==b) return sum[k];
int mid=(l+r)>>;
if(b<=mid) return querys(k<<,l,mid,a,b);
else if(a>mid) return querys(k<<|,mid+,r,a,b);
else return querys(k<<,l,mid,a,mid)+querys(k<<|,mid+,r,mid+,b);
}
int querym(int k,int l,int r,int a,int b)
{
if(l==a&&r==b) return mx[k];
int mid=(l+r)>>;
if(b<=mid) return querym(k<<,l,mid,a,b);
else if(a>mid) return querym(k<<|,mid+,r,a,b);
else return max(querym(k<<,l,mid,a,mid),querym(k<<|,mid+,r,mid+,b));
}
int main()
{
n=read();int a,b,res,T;char ch[];
for(int i=;i<n;i++) {a=read(),b=read();add(a,b);add(b,a);}
dfs();cnt=;Dfs(,);
for(int i=;i<=n;i++) mdf(,,n,hsh[i],read());
T=read();
while(T--)
{
scanf("%s",ch);a=read(),b=read();
if(ch[]=='C') mdf(,,n,hsh[a],b);
else if(ch[]=='M')
{
res=-inf;
while(bl[a]!=bl[b])
{
if(dep[bl[a]]<dep[bl[b]]) swap(a,b);
res=max(res,querym(,,n,hsh[bl[a]],hsh[a]));
a=fa[bl[a]];
}
res=max(res,querym(,,n,min(hsh[a],hsh[b]),max(hsh[a],hsh[b])));
printf("%d\n",res);
}
else if(ch[]=='S')
{
res=;
while(bl[a]!=bl[b])
{
if(dep[bl[a]]<dep[bl[b]]) swap(a,b);
res+=querys(,,n,hsh[bl[a]],hsh[a]);
a=fa[bl[a]];
}
res+=querys(,,n,min(hsh[a],hsh[b]),max(hsh[a],hsh[b]));
printf("%d\n",res);
}
}
}

bzoj 1036 树的统计Count的更多相关文章

  1. BZOJ 1036 树的统计Count 树链剖分模板题

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1036 题目大意: 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将 ...

  2. [置顶] bzoj 1036 树的统计Count 点权值模板

    树链剖分 点权型可做模板,链路剖分的思想把点hash到线段树的上,然后可通过n*(log(n)*log(n))的复杂度在树上操作,在线段树上能操作的在链路上都能操作. #include<cstd ...

  3. BZOJ - 1036 树的统计Count (LCT)

    LCT试炼题(代码量居然完爆树剖?) #include<bits/stdc++.h> using namespace std; ,inf=0x3f3f3f3f; ],flp[N],n,m, ...

  4. BZOJ - 1036 树的统计Count (树链剖分+线段树)

    题目链接 #include<bits/stdc++.h> using namespace std; typedef long long ll; ,inf=0x3f3f3f3f; ],mx[ ...

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

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

  6. Codevs 2460 == BZOJ 1036 树的统计

     2460 树的统计 2008年省队选拔赛浙江 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 一棵树上有n个节点,编号分别为1 ...

  7. BZOJ 1036 树的统计

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

  8. HYSBZ 1036 树的统计Count(树链剖分)题解

    思路: 树链剖分,不知道说什么...我连模板都不会用 代码: #include<map> #include<ctime> #include<cmath> #incl ...

  9. BZOJ 1036 树的统计(树链剖分)

    点权树链剖分模板题. # include <cstdio> # include <cstring> # include <cstdlib> # include &l ...

随机推荐

  1. 前端请求操作类型(get post put delete)

    get:获取数据 post:增加 put:修改 delete:删除

  2. 使用JS获取request参数

    1.document.write('<%=request.getAttribute("param")%>'); 2.window.navigator.userAgent ...

  3. mysql外键是多个id组成的字符串,查询方法

    借鉴:mysql使用instr达到in(字符串)的效果 结论:select * from 表名where INSTR(CONCAT(字符串),CONCAT(表id)) 问题来源:一表中的某字段是另一表 ...

  4. Codeforces Round #470 Div. 2题解

    A. Protect Sheep time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  5. 「 Luogu P2285 」打鼹鼠

    解题思路 第一眼看上去觉得要设计一个三维的 DP,$dp[i][j][k]$ 表示在 $(i,j)$ 这个位置上 $k$ 时刻能够打死的最多的鼹鼠. 但是被数据范围卡死.完全开不开数组啊. 然后注意到 ...

  6. linux whereis-查找二进制程序、代码等相关文件路径

    推荐:更多Linux 文件查找和比较 命令关注:linux命令大全 whereis命令用来定位指令的二进制程序.源代码文件和man手册页等相关文件的路径. whereis命令只能用于程序名的搜索,而且 ...

  7. HDU 5217 Brackets

    [题意概述] 给出一个有左括号和右括号的序列,左边的左括号和右边的右括号可以合并.现在要求你维护这个序列,支持两种操作: 1,翻转某个位置的括号: 2,查询区间[L,R]合并后第k个括号在原序列中的位 ...

  8. [bzoj4591][Shoi2015][超能粒子炮·改] (lucas定理+组合计数)

    Description 曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加 强大的粒子流的神秘装置.超能粒子炮·改相比超能粒子炮,在威 ...

  9. Prüfer序列和cayley定理

    参考资料: 1.matrix67 <经典证明:Prüfer编码与Cayley公式> 2.百度百科 3.Forget_forever prufer序列总结 4.维基百科 5.dirge的学习 ...

  10. Unity对象的所有组件深拷贝与粘贴

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/51454847 作者:car ...