【BZOJ1146】网络管理(线段树)

    来来来权限题但是有入门OJ的传送门

I Think

    题意:伟大的树上带修改第k大
    思路&实现:对于每个点建一颗权值线段树,维护其到根节点路径上的所有点权。查询(a,b)第k大时先找到lc=Lca(a,b),再用a b树上节点size和-lc与Fa[lc]树上节点size和决定如何左右递归就好。
    Attention!
    1)局部变量要注意初始化(比如说Query里的tmp)
    2)在删除节点调用del(int &rt)不能丢&(类似Swap函数也是)
    3)用于离散化的B[]数组,由于可能加入更新的值,所以大小要开得比N大
    4)计算Lca时,u和v的判等需要放在前面的if外,因为题目并没有说不能查询两个相同的点。
    鉴于以上错误,成功刷新了自己的调题时间记录……

    先上一份会TLE的代码,准备有时间再打一份只有修改值使用树状数组结合的。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) x&(-x)
using namespace std;
template <typename T> void read(T &x) {
    T f=1;x=0; char ch=getchar();
    while(ch>'9'||ch<'0') { if(ch=='-') f=-1;ch=getchar(); }
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=f;
}
const int sm = 8e4+5;
const int sn = sm*300;
int N,Q,tot,cnt;
int A[sm],B[sm<<1],C[sn],Ls[sn],Rs[sn];
int Lt[sm],Rt[sm],dep[sm],Fa[sm][20];
int hd[sm<<1],to[sm<<1],nxt[sm<<1];
struct query {
    int x,y,z;
}q[sm];
void Swap(int &x,int &y) { int t=x;x=y;y=t; }
void add(int f,int t) {
    to[++tot]=t,nxt[tot]=hd[f],hd[f]=tot;
    to[++tot]=f,nxt[tot]=hd[t],hd[t]=tot;
}
int Hash(int x) {
    return lower_bound(B+1,B+cnt+1,x)-B;
}
void Insert(int &rt,int l,int r,int p,int val) {
    if(!rt) rt=++tot; C[rt]+=val;
    if(l==r) return ;
    int m=(l+r)>>1;
    if(p<=m) Insert(Ls[rt],l,m,p,val);
    else Insert(Rs[rt],m+1,r,p,val);
}
void Dfs(int x,int f) {
    dep[x]=dep[Fa[x][0]=f]+1,Lt[x]=++tot;
    for(int i=1;i<20;++i)
        Fa[x][i]=Fa[Fa[x][i-1]][i-1];
    for(int i=hd[x];i;i=nxt[i]) 
        if(to[i]!=f) Dfs(to[i],x);
    Rt[x]=tot;
}
int Lca(int u,int v) {
    if(dep[u]!=dep[v]) {
        if(dep[u]<dep[v])Swap(u,v);
        for(int i=19;i>=0;--i)
            if(dep[Fa[u][i]]>dep[v]) u=Fa[u][i];
        u=Fa[u][0];
    }   
    if(u==v) return u;
    for(int i=19;i>=0;--i)
        if(Fa[u][i]!=Fa[v][i]) u=Fa[u][i],v=Fa[v][i];
    return Fa[u][0];
}
struct BIT {
    int root[sn];
    BIT() { memset(root,0,sizeof(root)); }
    void Modify(int x,int p,int val) {
        for(int i=x;i<=N;i+=lowbit(i))  
            Insert(root[i],1,cnt,p,val);
    }
    void Add(int l,int r,int p,int val) {
        Modify(l,p,val),Modify(r+1,p,-val);
    }
    void Query(int k,int a,int b) {
        int lc=Lca(a,b),l=1,r=cnt,m;
        int rt[4][30],n[4]={0,0,0,0},flag[4]={1,1,-1,-1};
        int pos[4]={Lt[a],Lt[b],Lt[lc],Lt[Fa[lc][0]]};
        if(dep[a]+dep[b]-dep[lc]-dep[Fa[lc][0]]<k) 
            puts("invalid request!");
        else {
            for(int i=0;i<4;++i) 
                for(int j=pos[i];j;j-=lowbit(j))
                    rt[i][++n[i]]=root[j];
            while(l<r) {
                int tmp=0;m=(l+r)>>1;
                for(int i=0;i<4;++i) 
                    for(int j=1;j<=n[i];++j)
                        if(rt[i][j]) tmp+=C[Rs[rt[i][j]]]*flag[i];
                if(k<=tmp) {
                    l=m+1;
                    for(int i=0;i<4;++i) 
                        for(int j=1;j<=n[i];++j)
                            if(rt[i][j])rt[i][j]=Rs[rt[i][j]];
                } else {
                    r=m,k-=tmp;
                    for(int i=0;i<4;++i) 
                        for(int j=1;j<=n[i];++j)
                            if(rt[i][j])rt[i][j]=Ls[rt[i][j]];
                }
            }
            printf("%d\n",B[l]);
        }
    }
}tree;
int main() {
    read(N),read(Q);
    for(int i=1;i<=N;++i) read(A[i]),B[++cnt]=A[i];
    for(int i=1,x,y,z;i<N;++i) read(x),read(y),add(x,y);
    tot=0,Dfs(1,0),tot=0;
    for(int i=1;i<=Q;++i) {
        read(q[i].x),read(q[i].y),read(q[i].z);
        if(!q[i].x) B[++cnt]=q[i].z;
    }
    sort(B+1,B+cnt+1);
    cnt=unique(B+1,B+cnt+1)-B-1;
    for(int i=1;i<=N;++i)
        tree.Add(Lt[i],Rt[i],Hash(A[i]),1);
    for(int i=1;i<=Q;++i) 
        if(!q[i].x) {
            tree.Add(Lt[q[i].y],Rt[q[i].y],Hash(A[q[i].y]),-1);
            tree.Add(Lt[q[i].y],Rt[q[i].y],Hash(q[i].z),1);
            A[q[i].y]=q[i].z;
        }
        else tree.Query(q[i].x,q[i].y,q[i].z);
    return 0;
}

来一份AC代码~

#include<cstdio>
#include<algorithm>
#define lowbit(x) x&(-x)

const int sm = 8e4+5;
const int Sn = sm*128;

int N,Q,tot,cnt,ss;
int C[Sn],Rs[Sn],Ls[Sn];
int A[sm],B[sm<<1],St[sm],Rt[sm];
int to[sm<<1],nxt[sm<<1],hd[sm];
int Fa[sm],tp[sm],sn[sm],sz[sm],dp[sm],pl[sm],en[sm];
struct Que {
    int k,a,b;
}q[sm];

namespace Tree {
    int use[4][sm];
    template <typename T> void read(T &x) {
        char ch=getchar();x=0;int f=1;
        while(ch>'9'||ch<'0') { if(ch=='-')f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        x*=f;
    }
    void Add(int u,int v) {
        to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot;
        to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot;
    }
    void Swap(int &x,int &y) { int t=x;x=y;y=t; }
    int Hash(int x) { return std::lower_bound(B+1,B+cnt+1,x)-B; }

    int Insert(int pre,int l,int r,int p,int val) {
        int cur=++tot; C[cur]=C[pre]+val;
        if(l==r) return cur; int m=(l+r)>>1;
        if(p<=m) Ls[cur]=Insert(Ls[pre],l,m,p,val),Rs[cur]=Rs[pre];
        if(p >m) Rs[cur]=Insert(Rs[pre],m+1,r,p,val),Ls[cur]=Ls[pre];
        return cur;
    }
    void Dfsa(int x,int fa) {
        dp[x]=dp[fa]+1,Fa[x]=fa;
        sn[x]=0,sz[x]=1;
        Rt[x]=Insert(Rt[fa],1,cnt,Hash(A[x]),1);
        for(int i=hd[x];i;i=nxt[i])
            if(to[i]!=fa) {
                Dfsa(to[i],x);
                sz[x]+=sz[to[i]];
                if(sz[to[i]]>sz[sn[x]])
                    sn[x]=to[i];
            }
    }
    void Dfsb(int x,int top) {
        tp[x]=top,pl[x]=++ss;
        if(sn[x]) Dfsb(sn[x],top);
        for(int i=hd[x];i;i=nxt[i])
            if(to[i]!=Fa[x]&&to[i]!=sn[x])
                Dfsb(to[i],to[i]);
        en[x]=ss;
    }
    int Lca(int u,int v) {
        while(tp[u]!=tp[v]){
            if(dp[tp[u]]<dp[tp[v]])Swap(u,v);
            u=Fa[tp[u]];
        }
        if(dp[u]>dp[v])Swap(u,v);
        return u;
    }
    void TModify(int u,int v,int p,int val) {
        for(int i=u;i<=N;i+=lowbit(i))    
            St[i]=Insert(St[i],1,cnt,p,val);
        for(int i=v;i<=N;i+=lowbit(i))
            St[i]=Insert(St[i],1,cnt,p,-val);
    }
    int Sum(int x,int y) {
        int res=0;
        for(int i=1;i<=y;++i)
            res+=C[Rs[use[x][i]]];
        return res;
    }
    void RQuery(int a,int b,int K) {
        int l=1,r=cnt,Lc=Lca(a,b),Gc=Fa[Lc];
        if(dp[a]+dp[b]-dp[Lc]-dp[Gc]<K) { printf("invalid request!\n"); return ; }
        int ct[4]={0,0,0,0},tmp[4]={pl[a],pl[b],pl[Lc],pl[Gc]};
        for(int i=0;i<4;++i)
            for(int j=tmp[i];j;j-=lowbit(j))
                use[i][++ct[i]]=St[j];
        a=Rt[a],b=Rt[b],Lc=Rt[Lc],Gc=Rt[Gc];
        while(l<r) {
            int m=(l+r)>>1,tmp;
            tmp=C[Rs[a]]+C[Rs[b]]+Sum(0,ct[0])+Sum(1,ct[1])-C[Rs[Lc]]-C[Rs[Gc]]-Sum(2,ct[2])-Sum(3,ct[3]);
            if(tmp<K) {
                K-=tmp,r=m;  a=Ls[a],b=Ls[b],Lc=Ls[Lc],Gc=Ls[Gc];
                for(int i=0;i<4;++i)
                    for(int j=1;j<=ct[i];++j)
                        use[i][j]=Ls[use[i][j]];
            }
            else {
                a=Rs[a],b=Rs[b],Lc=Rs[Lc],Gc=Rs[Gc],l=m+1;
                for(int i=0;i<4;++i)
                    for(int j=1;j<=ct[i];++j)
                        use[i][j]=Rs[use[i][j]];
            }
        }
        printf("%d\n",B[l]);
    }
}

int main() {
    using namespace Tree;
    read(N),read(Q);
    for(int i=1;i<=N;++i) read(A[i]),B[++cnt]=A[i];
    for(int i=1,u,v;i< N;++i) 
        read(u),read(v),Add(u,v);
    for(int i=1;i<=Q;++i) {
        read(q[i].k),read(q[i].a),read(q[i].b);
        if(!q[i].k) B[++cnt]=q[i].b;
    }

    std::sort(B+1,B+cnt+1);
    cnt=std::unique(B+1,B+cnt+1)-B-1;

    tot=0,Dfsa(1,0),Dfsb(1,1);

    for(int i=1;i<=Q;++i) {
        if(q[i].k) RQuery(q[i].a,q[i].b,q[i].k);
        if(!q[i].k) {
            TModify(pl[q[i].a],en[q[i].a]+1,Hash(A[q[i].a]),-1);
            TModify(pl[q[i].a],en[q[i].a]+1,Hash(A[q[i].a]=q[i].b),1);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值