昨天刚学了树链剖分,突然想起来去年第一次参加比赛的时候,也有类似的题目没有做出来,当时比较懒惰,赛后没补,现在翻回来补补题,然后发现这题居然是道简单题,吐血
可惜了,当年要是勤快一点,提前学了树链剖分,没准就金了,
遂记此题解以作警示,不可再让机会白白溜走了
题解
很基础的树链剖分+线段树
涉及到开根号只能单点修改,这里要注意一下,每次都单点修改会T,特判一下当前点的权值是否为1或者为0,避免重复操作
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N=2e5+10;
ll a[N];
int n,q;
struct egde{
int to,next;
}e[N];
int head[N],tot;
void add(int u,int v){
e[++tot]={v,head[u]};
head[u]=tot;
}
int f[N],dep[N],son[N],sz[N];
void dfs1(int u,int fa){
dep[u]=dep[fa]+1;
f[u]=fa;
sz[u]=1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v!=fa){
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])
son[u]=v;
}
}
}
int id[N],top[N],dfn;
ll w[N];
void dfs2(int u,int t){
top[u]=t;
id[u]=++dfn;
w[dfn]=a[u];
if(son[u])dfs2(son[u],t);
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v!=f[u] && v!=son[u])
dfs2(v,v);
}
}
int lazy[N];//记录要更新多少次
bool flag[N];//判断区间值是否为1或0 防T
ll t[N*4];
void pushup(int rt){
t[rt]=t[rt<<1]+t[rt<<1|1];
flag[rt]=(flag[rt<<1]&&flag[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l==r){
t[rt]=w[l];
return;
}
int mid=l+r>>1;
build(lson);
build(rson);
pushup(rt);
}
void update(int L,int R,int l,int r,int rt){//暴力开根号
if(flag[rt])return;//1无法再更新 0区间内有点还可以修改
if(l==r){//单点修改
t[rt]=(ll)sqrt(t[rt]);
if(t[rt]==0||t[rt]==1) flag[rt]=1;
return;
}
int mid=l+r>>1;
if(L<=mid)update(L,R,lson);
if(R>mid)update(L,R,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l &&r<=R){
return t[rt];
}
ll res=0;
int mid=l+r>>1;
if(L<=mid)res+=query(L,R,lson);
if(R>mid)res+=query(L,R,rson);
return res;
}
void updRange(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]] < dep[top[v]])
swap(u,v);//u链顶深
update(id[top[u]],id[u],1,n,1);
u=f[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
update(id[u],id[v],1,n,1);
}
ll qRange(int u,int v){
ll res=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
res+=query(id[top[u]],id[u],1,n,1);
u=f[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
res+=query(id[u],id[v],1,n,1);
return res;
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>q;
for (int i = 1; i <= n; ++i) {
cin>>a[i];
}
for (int i = 1,u,v; i < n; ++i) {
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(1,0);
dfs2(1,1);
build(1,n,1);
for (int i = 1,op,u,v; i <= q; ++i) {
cin>>op>>u>>v;
if(op==0){
updRange(u,v);
}else{
cout <<qRange(u,v) << endl;
}
}
return 0;
}