cf276E 两棵线段树分别维护dfs序和bfs序,好题回头再做

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

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

 

转载于:https://www.cnblogs.com/zsben991126/p/9926270.html

你可能感兴趣的:(cf276E 两棵线段树分别维护dfs序和bfs序,好题回头再做)