zoukankan      html  css  js  c++  java
  • cf276E 两棵线段树分别维护dfs序和bfs序,好题回头再做

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

    /*
    对于每次更新,先处理其儿子方向,再处理其父亲方向
    处理父亲方向时无法达到根,那么直接更新
    如果能达到根,那么到兄弟链中去更新,使用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=0;i<mp[u].size();i++){
            int v=mp[u][i];
            if(v==from) continue;
            Dfs(v,u,dis+1);
        }
        R[u]=cnt;
    }
    //处理bfs序的方法
    void Bfs(){
        int tot=0;
        queue<node>s;
        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<mp[now.u].size();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
    ",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<dist[u])//如果根到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);
                    }
                }
            }
        }
    }
  • 相关阅读:
    Ios 从无到有项目 MVVM模式(两)
    国外论文搜索
    memcpy的使用方法总结
    简单工厂模式
    curl命令具体解释
    java.lang.Math中的基本方法
    海量数据处理面试题集锦
    BEGINNING SHAREPOINT&#174; 2013 DEVELOPMENT 文件夹
    TinyXml高速入门(一)
    Android SDK 2.2 离线安装
  • 原文地址:https://www.cnblogs.com/zsben991126/p/9926270.html
Copyright © 2011-2022 走看看