题目:树的统计
思路:树剖
参考:
吊打集训队的zcy的代码
几乎是照着抄的……
数据生成器:
#include<bits/stdc++.h>
using namespace std;
#define maxn 10
#define maxm 10
#define maxa 10
#define Rand() (rand()+rand()%19260817)
int fa[maxn+5]= {0};
int find(int x) {
if(fa[x]==0) return x;
return fa[x]=find(fa[x]);
}
int main() {
srand(time(NULL));
int n,m;
n=Rand()%maxn+1;
m=Rand()%maxm+1;
printf("%d\n",n);
for(int i=1; i<n; i++) {
int l=0,r=0;
while(find(l)==find(r)) {
l=Rand()%n+1;
r=n-Rand()%n;
}
int x=find(l),y=find(r);
fa[x]=y;
printf("%d %d\n",l,r);
}
for(int i=1; i<=n; i++) printf("%d ",Rand()%maxn+1);
printf("\n%d\n",m);
while(m--) {
int opr=Rand()%3;
if(opr==0) printf("QMAX ");
if(opr==1) printf("QSUM ");
if(opr==2) printf("CHANGE ");
int l=1,r=0;
l=Rand()%n+1;
r=n-Rand()%n;
printf("%d %d\n",l,r);
}
return 0;
}
代码:
有注释版:
using namespace std;
#define maxn 400000
#define inf (1<<30)
int n,m;
vector<int> g[maxn+5]; //原图
int a[maxn+5]= {0}; //点权
int d[maxn+5],fa[maxn+5]; //深度、父节点
int sz[maxn+5],wson[maxn+5]; //子树节点个数,重儿子
int pre[maxn+5]= {0}; //节点的新编号
int top[maxn+5]= {0}; //新编号对应的节点
int tpos[maxn+5]= {0} //链顶的位置
int cnt=0; //计数器
int maxv[maxn+5]= {0},sumv[maxn+5]= {0}; //区间最大值,区间和
void push_up(int o,int lch,int rch) { //线段树上传信息
sumv[o]=sumv[lch]+sumv[rch];
maxv[o]=max(maxv[lch],maxv[rch]);
}
void update(int o,int l,int r,int p,int v) { //线段树单点修改
int mid=(r-l)/2+l;
if(p<l||p>r) return ;
if(l==r) {
sumv[o]=maxv[o]=v;
return ;
}
int lch=o*2,rch=lch+1;
update(lch,l,mid,p,v),update(rch,mid+1,r,p,v);
push_up(o,lch,rch);
}
void build(int o,int l,int r) { //线段树建树
if(l==r) {
sumv[o]=maxv[o]=a[pre[l]];
return ;
}
int mid=(r-l)/2+l;
int lch=o*2,rch=lch+1;
build(lch,l,mid),build(rch,mid+1,r);
push_up(o,lch,rch);
}
void readin() { //读入
scanf("%d",&n);
for(int i=1; i<n; i++) {
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
scanf("%d",&m);
}
int querymax(int o,int l,int r,int P,int Q) { //线段树区间查询max
if(P<=l&&r<=Q) return maxv[o];
else if(P>r||Q<l) return -inf;
int mid=l+(r-l)/2;
int lch=o*2,rch=lch+1;
return max(querymax(lch,l,mid,P,Q),querymax(rch,mid+1,r,P,Q));
}
int querysum(int o,int l,int r,int P,int Q) { //线段树区间查询sum
if(P<=l&&r<=Q) return sumv[o];
else if(P>r||Q<l) return 0;
int mid=l+(r-l)/2;
int lch=o*2,rch=lch+1;
return querysum(lch,l,mid,P,Q)+querysum(rch,mid+1,r,P,Q);
}
int querym(int u,int v) { //询问max
int ans=-inf;
while(top[u]!=top[v]) { //没走到LCA
if(d[top[u]]<d[top[v]]) swap(u,v); //始终保证u的深度较大
ans=max(ans,querymax(1,1,n,tpos[top[u]],tpos[u]));
u=fa[top[u]];
}
if(d[u]<d[v]) swap(u,v);
ans=max(ans,querymax(1,1,n,tpos[v],tpos[u]));
return ans;
}
int querys(int u,int v) { //询问sum
int ans=0;
while(top[u]!=top[v]) {
if(d[top[u]]<d[top[v]]) swap(u,v);
ans+=querysum(1,1,n,tpos[top[u]],tpos[u]);
u=fa[top[u]];
}
if(d[u]<d[v]) swap(u,v);
ans+=querysum(1,1,n,tpos[v],tpos[u]);
return ans;
}
void dfs1(int x,int f) { //处理sz[],d[],fs[],wson[]
sz[x]=1;
for(int i=0; i<g[x].size(); i++) {
int y=g[x][i];
if(y==f) continue;
d[y]=d[x]+1,fa[y]=x;
dfs1(y,x);
sz[x]+=sz[y];
if(sz[y]>sz[wson[x]]) wson[x]=y;
}
}
void dfs2(int x,int tp) { //重新编号
tpos[x]=++cnt;
pre[cnt]=x;
top[x]=tp;
if(wson[x]) {
dfs2(wson[x],tp);
}
for(int i=0; i<g[x].size(); i++) {
int y=g[x][i];
if(y==fa[x]||y==wson[x]) continue;
dfs2(y,y);
}
}
int main() {
readin();
d[1]=1,fa[1]=1; //默认1为根
dfs1(1,-1),dfs2(1,1);
build(1,1,n);
while(m--) {
char s[10];
int x,y;
scanf("%s%d%d",s,&x,&y);
if(s[1]=='H') {
update(1,1,n,tpos[x],y);
} else if(s[1]=='M') {
printf("%d\n",querym(x,y));
} else if(s[1]=='S') {
printf("%d\n",querys(x,y));
}
}
return 0;
}
无注释精简版:
#include<bits/stdc++.h>
using namespace std;
#define maxn 400000
#define inf (1<<30)
int n,m;
vector<int> g[maxn+5];
int a[maxn+5]= {0};
int d[maxn+5],fa[maxn+5];
int sz[maxn+5],wson[maxn+5];
int top[maxn+5]= {0};
int tpos[maxn+5]= {0},pre[maxn+5]= {0};
int cnt=0;
int maxv[maxn+5]= {0},sumv[maxn+5]= {0};
void push_up(int o,int lch,int rch) {
sumv[o]=sumv[lch]+sumv[rch];
maxv[o]=max(maxv[lch],maxv[rch]);
}
void update(int o,int l,int r,int p,int v) {
int mid=(r-l)/2+l;
if(p<l||p>r) return ;
if(l==r) {
sumv[o]=maxv[o]=v;
return ;
}
int lch=o*2,rch=lch+1;
update(lch,l,mid,p,v),update(rch,mid+1,r,p,v);
push_up(o,lch,rch);
}
void build(int o,int l,int r) {
if(l==r) {
sumv[o]=maxv[o]=a[pre[l]];
return ;
}
int mid=(r-l)/2+l;
int lch=o*2,rch=lch+1;
build(lch,l,mid),build(rch,mid+1,r);
push_up(o,lch,rch);
}
void readin() {
scanf("%d",&n);
for(int i=1; i<n; i++) {
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
scanf("%d",&m);
}
void dfs1(int x,int f) {
sz[x]=1;
for(int i=0; i<g[x].size(); i++) {
int y=g[x][i];
if(y==f) continue;
d[y]=d[x]+1,fa[y]=x;
dfs1(y,x);
sz[x]+=sz[y];
if(sz[y]>sz[wson[x]]) wson[x]=y;
}
}
void dfs2(int x,int tp) {
tpos[x]=++cnt;
pre[cnt]=x;
top[x]=tp;
if(wson[x]) {
dfs2(wson[x],tp);
}
for(int i=0; i<g[x].size(); i++) {
int y=g[x][i];
if(y==fa[x]||y==wson[x]) continue;
dfs2(y,y);
}
}
int querymax(int o,int l,int r,int P,int Q) {
if(P<=l&&r<=Q) return maxv[o];
else if(P>r||Q<l) return -inf;
int mid=l+(r-l)/2;
int lch=o*2,rch=lch+1;
return max(querymax(lch,l,mid,P,Q),querymax(rch,mid+1,r,P,Q));
}
int querym(int u,int v) {
int ans=-inf;
while(top[u]!=top[v]) {
if(d[top[u]]<d[top[v]]) swap(u,v);
ans=max(ans,querymax(1,1,n,tpos[top[u]],tpos[u]));
u=fa[top[u]];
}
if(d[u]<d[v]) swap(u,v);
ans=max(ans,querymax(1,1,n,tpos[v],tpos[u]));
return ans;
}
int querysum(int o,int l,int r,int P,int Q) {
if(P<=l&&r<=Q) return sumv[o];
else if(P>r||Q<l) return 0;
int mid=l+(r-l)/2;
int lch=o*2,rch=lch+1;
return querysum(lch,l,mid,P,Q)+querysum(rch,mid+1,r,P,Q);
}
int querys(int u,int v) {
int ans=0;
while(top[u]!=top[v]) {
if(d[top[u]]<d[top[v]]) swap(u,v);
ans+=querysum(1,1,n,tpos[top[u]],tpos[u]);
u=fa[top[u]];
}
if(d[u]<d[v]) swap(u,v);
ans+=querysum(1,1,n,tpos[v],tpos[u]);
return ans;
}
int main() {
readin();
d[1]=1,fa[1]=1;
dfs1(1,-1),dfs2(1,1);
build(1,1,n);
while(m--) {
char s[10];
int x,y;
scanf("%s%d%d",s,&x,&y);
if(s[1]=='H') {
update(1,1,n,tpos[x],y);
} else if(s[1]=='M') {
printf("%d\n",querym(x,y));
} else if(s[1]=='S') {
printf("%d\n",querys(x,y));
}
}
return 0;
}