搞了一晚上,错了,以后回头再来看

/*
对于每次更新,先处理其儿子方向,再处理其父亲方向
处理父亲方向时无法达到根,那么直接更新
如果能达到根,那么到兄弟链中去更新,使用bfs序
最后,查询结点v的结果就是dfs序线段树上的查询值+bfs线段树上的查询值
*/
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define maxn 150005
int n,q;
vector<int> mp[maxn]; struct node{
int u,depth;
}now,nex;
int depthL[maxn];//深度为i的下标最小的点
int depthR[maxn];//深度为i的下标最大的点
int num[maxn];//bfs序
int vis[maxn]; int L[maxn];//dfs入序
int R[maxn];//某结点为根的最大深度
int dist[maxn];
int cnt;
void Dfs(int u,int from,int dis){
L[u]=++cnt;
dist[u]=dis;
for(int i=;i<mp[u].size();i++){
int v=mp[u][i];
if(v==from) continue;
Dfs(v,u,dis+);
}
R[u]=cnt;
}
//处理bfs序的方法
void Bfs(){
int tot=;
queue<node>s;
now.u=,now.depth=;
s.push(now);
memset(depthL,-,sizeof depthL);
memset(depthR,,sizeof depthR);
memset(vis,,sizeof vis);
vis[]=;
while(!s.empty()){
tot++;
now=s.front();
s.pop();
num[now.u]=tot;
if(depthL[now.depth==-])
depthL[now.depth]=num[now.u];
depthR[now.depth]=max(depthR[now.depth],num[now.u]);
for(int i=;i<mp[now.u].size();i++){
int v=mp[now.u][i];
if(vis[v]==){
vis[v]=;
nex.u=v;
nex.depth=now.depth+;
s.push(nex);
}
}
}
}
//第一棵线段树处理dfs上的修改和查询,因为所有的子树都是链,其dfs连续,所以直接用线段树区间更新
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int tree[maxn<<];
int flag[maxn<<];
inline void pushup(int rt){
tree[rt]=tree[rt<<]+tree[rt<<|];
}
inline void pushdown(int l,int r,int rt){
if(flag[rt]){
int m=l+r>>;
flag[rt<<]+=flag[rt];
tree[rt<<]=(m-l+)*flag[rt];
tree[rt<<|]=(r-m)*flag[rt];
flag[rt]=;
}
}
void build(int l,int r,int rt){
tree[rt]=flag[rt]=;
if(l==r) return;
int m=l+r>>;
pushdown(l,r,rt);
build(lson);
build(rson);
pushup(rt);
}
void update(int L,int R,int c,int l,int r,int rt){
if(L<=l && R>=r){
tree[rt]+=(r-l+)*c;
flag[rt]+=c;
return;
}
int m=l+r>>;
pushdown(l,r,rt);
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
pushup(rt);
}
//是单点查询
int query(int p,int l,int r,int rt){
if(l==r) return tree[rt];
int m=l+r>>;
pushdown(l,r,rt);
if(p<=m) return query(p,lson);
if(p>m) return query(p,rson);
pushup(rt);
} //第二棵线段树用来处理bfs上的修改和查询
//bfs序线段树也是通过访问顺序维护信息
int sum[maxn<<];
int flag2[maxn<<];
inline void pushup2(int rt){
sum[rt]=sum[rt<<]+sum[rt<<|];
}
inline void pushdown2(int l,int r,int rt){
if(flag2[rt]){
int m=l+r>>;
flag2[rt>>]+=flag2[rt];
flag2[rt>>|]+=flag2[rt];
sum[rt>>]+=(m-l+)*flag2[rt];
sum[rt>>|]+=(r-m)*flag2[rt];
flag2[rt]=;
}
}
void build2(int l,int r,int rt){
sum[rt]=flag2[rt]=;
if(l==r) return;
int m=l+r>>;
pushdown2(l,r,rt);
build(lson);
build(rson);
pushup2(rt);
}
void update2(int L,int R,int c,int l,int r,int rt){
if(L<=l && R>=r){
sum[rt]+=(r-l+)*c;
flag2[rt]+=c;
return;
}
int m=l+r>>;
pushdown2(l,r,rt);
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
pushup2(rt);
}
int query2(int p,int l,int r,int rt){
if(l==r) return sum[rt];
int m=l+r>>;
pushdown2(l,r,rt);
if(p<=m) return query2(p,lson);
if(p>m) return query2(p,rson);
pushup2(rt);
} int main(){
while(scanf("%d%d",&n,&q)==){
for(int i=;i<=n;i++)
mp[i].clear();
for(int i=;i<=n-;i++){
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
cnt=;
Dfs(,-,);
Bfs();
build(,n,);
build2(,n,);
while(q--){
int op;
scanf("%d",op);
if(op==){//查询结点x的值
int x;
scanf("%d",&x);
printf("%d\n",query(L[x],,n,)+query2(num[x],,n,));
}
else {
int u,v,d;scanf("%d%d%d",&u,&v,&d);
if(u==){//如果是根结点,直接在兄弟结点上更新
if(depthR[d]!=)//这个深度是有节点的
update2(,depthR[d],v,,n,);
else //这个深度没有结点了,整棵树更新
update2(,n,v,,n,);
continue;
}
//如果不是根结点上更新
//先在dfs序上更新,注意
update(L[u],min(L[u]+d,R[u]),v,,n,);
if(d<dist[u])//如果根到u距离大于d,直接在链上更新
update(L[u]-d,L[u]-,v,,n,);
else {
//先从根维护到u的父亲
update(L[u]-(dist[u]-),L[u]-,v,,n,);
update(L[u]-(dist[u]-),min(L[u]-(dist[u]-)+(d-dist[u]-),R[u]),-v,,n,);//取消root到其兄弟结点相同深度的相应修改,因为接下去bfs序修改会重复
if(depthR[d-dist[u]]!=)//如果这个深度有结点
update2(,depthR[d-dist[u]],v,,n,);
else
update2(,n,v,,n,);
}
}
}
}
}
05-08 15:10