BZOJ1146: [CTSC2008]网络管理Network

走远了吗. 提交于 2019-11-28 19:02:49

题意

树链上带修改第K大

思路

树链剖分+线段树套平衡树+二分

具体就是先树剖把树映射到区间,然后对区间建线段树,线段树的每一个节点是一颗权值平衡树,修改就是在线段树上跑一遍,对于经过的线段树节点,其实就是平衡树,做一次删除和一次添加。查询就是二分最终的答案ans,然后计算链上大于ans的节点有多少,这一计算只需要在线段树上跑一遍,对于经过的线段树节点计算对应的平衡树里有多少大于ans的节点再加起来就可以了。

二分一个\(logn\),跑树链一个\(logn\),跑线段树一个\(logn\),查询平衡树一个\(logn\),一共\(O(mlog^4n)\)。我的代码跑了将近46s

树链剖分+树状数组套主席树

类似query on a tree,借助lca的性质来维护树链信息,然后由于带修改,所以在外套一个树状数组来处理修改。每次询问需要对\(logn\)颗主席树进行修改,一次修改\(logn\),一共\(O(mlog^2n)\)

WA到自闭,对着空气改了半天,最后发现是数组开小了

跑了大概8s

整体二分

留个坑不会整体二分

AC代码:思路一

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=4e5+5;
const int INF=1e9+7;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x<<3) + (x<<1) + ch - 48; ch = getchar(); }
    return x * f;
}



struct Treap{
    const static int N=maxn<<2;
    int L[N],R[N],v[N],p[N],A[N],C[N],tot;
    
    void init(){A[0]=L[0]=R[0]=C[0]=0;tot=1;}
    
    int newnode(int V,int P)
    {
        L[tot]=R[tot]=0;
        v[tot]=V;p[tot]=P;
        A[tot]=C[tot]=1;
        return tot++;
    }
    
    void Count(int x){C[x]=A[x]+C[L[x]]+C[R[x]];}
    
    void rotate_right(int &x)
    {
        int y=L[x];L[x]=R[y];R[y]=x;C[y]=C[x];Count(x);x=y;
    }
    
    void rotate_left(int &x)
    {
        int y=R[x];R[x]=L[y];L[y]=x;C[y]=C[x];Count(x);x=y;
    }
    
    void insert(int &x,int V,int P)
    {
        if(!x){x=newnode(V,P);return;}
        if(v[x]==V)++A[x];
        else if(V<v[x])
        {
            insert(L[x],V,P);
            if(p[x]>p[L[x]])rotate_right(x);
        }
        else
        {
            insert(R[x],V,P);
            if(p[x]>p[R[x]])rotate_left(x);
        }
        Count(x);
    }
    
    void Delete(int &x,int V)
    {
        if(!x)return;
        if(V<v[x])Delete(L[x],V);
        else if(V>v[x])Delete(R[x],V);
        else if(A[x]>1)--A[x];
        else if(!L[x] || !R[x])x=L[x]+R[x];
        else if(p[L[x]]<p[R[x]]){rotate_right(x);Delete(R[x],V);}
        else{rotate_left(x);Delete(L[x],V);}
        Count(x);
    }
    
    void del(int &x,int V){Delete(x,V);}
    void add(int &x,int V){insert(x,V,rand());}
    int getrank(int x,int V)
    {
        int ans=0;
        while(x)
        {
            if(V==v[x]){
                ans+=C[R[x]];
                break;
            }
            else if(V<v[x]){
                ans+=(C[R[x]]+A[x]);
                x=L[x];
            }
            else x=R[x];
        }
        return ans;
    }
}treap;






struct Segment_Tree{
    int rt[maxn<<2];
    
    void init(){
        memset(rt,0,sizeof(rt));
    }
    
    void update(int x,int l,int r,int pos,int preV,int V){
        treap.del(rt[x],preV);
        treap.add(rt[x],V);
        if(l==r)return;
        int mid=(l+r)/2;
        if(pos<=mid)update(x<<1,l,mid,pos,preV,V);
        else update(x<<1|1,mid+1,r,pos,preV,V);
    }
    
    int query_rank(int x,int l,int r,int L,int R,int V){
        if(L==l && R==r){
            return treap.getrank(rt[x],V);
        }
        int mid=(l+r)/2;
        if(R<=mid)return query_rank(x<<1,l,mid,L,R,V);
        else if(L>mid)return query_rank(x<<1|1,mid+1,r,L,R,V);
        else return query_rank(x<<1,l,mid,L,mid,V)+query_rank(x<<1|1,mid+1,r,mid+1,R,V);
    }
}segtree;







int w[maxn];
int n,q;

int tot,head[maxn];
struct Edge{
    int v,nxt;
}e[maxn<<1];
inline void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
inline void addedge(int u,int v){
    e[tot].v=v;e[tot].nxt=head[u];
    head[u]=tot++;
    
    e[tot].v=u;e[tot].nxt=head[v];
    head[v]=tot++;
}






int sz[maxn],son[maxn],fa[maxn],h[maxn],A[maxn],pos[maxn],top[maxn],cnt;
void dfs1(int u,int f){
    int v;
    sz[u]=1;son[u]=0;fa[u]=f;h[u]=h[f]+1;
    for(int i=head[u];i!=-1;i=e[i].nxt){
        v=e[i].v;
        if(v==f)continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[son[u]]<sz[v])son[u]=v;
    }
}

void dfs2(int u,int f,int k){
    int v;
    top[u]=k;
    pos[u]=++cnt;
    A[cnt]=w[u];
    if(son[u])dfs2(son[u],u,k);
    for(int i=head[u];i!=-1;i=e[i].nxt){
        v=e[i].v;
        if(v==f)continue;
        if(v==son[u])continue;
        dfs2(v,u,v);
    }
}

int LCA(int u,int v){
    while(top[u]!=top[v]){
        if(h[top[u]]<h[top[v]])swap(u,v);
        u=fa[top[u]];
    }
    if(h[u]>h[v])swap(u,v);
    return u;
}

int query(int u,int v,int ww){
    int ans=0;
    while(top[u]!=top[v]){
        if(h[top[u]]<h[top[v]])swap(u,v);
        ans+=segtree.query_rank(1,1,n,pos[top[u]],pos[u],ww);
        u=fa[top[u]];
    }
    if(h[u]>h[v])swap(u,v);
    ans+=segtree.query_rank(1,1,n,pos[u],pos[v],ww);
    return ans;
}










int t[maxn<<1],m;
int k[maxn],a[maxn],b[maxn];

void unik(){
    sort(t+1,t+1+m);
    m=unique(t+1,t+1+m)-(t+1);
}
int Hash(int x){
    return lower_bound(t+1,t+1+m,x)-t;
}

int solve(int u,int v,int k){
    int lca=LCA(u,v);
    int sz=h[u]+h[v]-2*h[lca]+1;
    if(sz<k)return -1;
    
    int l=1,r=m,mid,ans;
    while(l<=r){
        int mid=(l+r)/2;
        int rk=query(u,lca,mid)+query(v,lca,mid);
        if(w[lca]>mid)rk--;
        if(rk<=k-1){
            r=mid-1;
            ans=mid;
        }else{
            l=mid+1;
        }
    }
    return t[ans];
}

int main()
{
    n=read();q=read(); 
    init();
    int u,v,ww;
    for(int i=1;i<=n;i++)w[i]=read(),t[++m]=w[i];
    for(int i=1;i<n;i++){
        u=read();v=read();
        addedge(u,v);
    }
    
    cnt=0;
    dfs1(1,0);
    dfs2(1,0,1);
    
    for(int i=1;i<=q;i++){
        k[i]=read();a[i]=read();b[i]=read();
        if(k[i]==0)t[++m]=b[i];
    }
    
    unik();
    for(int i=1;i<=n;i++)w[i]=Hash(w[i]);
    
    segtree.init();treap.init();
    for(int i=1;i<=n;i++)
        segtree.update(1,1,n,pos[i],0,w[i]);
    
    int ans; 
    for(int i=1;i<=q;i++){
        if(k[i]==0){
            int V=Hash(b[i]);
            segtree.update(1,1,n,pos[a[i]],w[a[i]],V);
            w[a[i]]=V;
        }
        else{
            ans=solve(a[i],b[i],k[i]);
            if(ans!=-1)printf("%d\n",ans);
            else printf("invalid request!\n");
        }
    }
    return 0;
}

AC代码:树状数组套主席树

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=16e4+5;
const int maxn=N;
int n,m;
int w[maxn],t[maxn],vnum;

struct Query{
    int k,a,b;
}q[maxn];




int addT[maxn],anum,subT[maxn],snum;
int T[maxn],L[maxn<<7],R[maxn<<7],sum[maxn<<7],tnum;
void update(int &rt,int l,int r,int x,int d){
    if(!rt)rt=++tnum;
    sum[rt]+=d;
    if(l<r){
        int mid=(l+r)/2;
        if(x<=mid)update(L[rt],l,mid,x,d);
        else update(R[rt],mid+1,r,x,d);
    }
}
int query(int l,int r,int k){
    if(l==r)return l;
    int tmp=0;
    for(int i=1;i<=anum;i++)tmp+=sum[R[addT[i]]];
    for(int i=1;i<=snum;i++)tmp-=sum[R[subT[i]]];
    int mid=(l+r)/2;
    if(k<=tmp){
        for(int i=1;i<=anum;i++)addT[i]=R[addT[i]];
        for(int i=1;i<=snum;i++)subT[i]=R[subT[i]];
        return query(mid+1,r,k);
    }
    else{
        for(int i=1;i<=anum;i++)addT[i]=L[addT[i]];
        for(int i=1;i<=snum;i++)subT[i]=L[subT[i]];
        return query(l,mid,k-tmp);
    }
}







int lowbit(int x){return x&(-x);}
void add(int x,int val,int d){
    for(;x<=n;x+=lowbit(x))
        update(T[x],1,vnum,val,d);
}








int head[maxn],tot=1;
struct Edge{
    int v,nxt;
}e[maxn<<1];
void addedge(int u,int v){
    e[tot].v=v;e[tot].nxt=head[u];head[u]=tot++;
    e[tot].v=u;e[tot].nxt=head[v];head[v]=tot++;
}
int sz[maxn],son[maxn],fa[maxn],h[maxn],pos[maxn],top[maxn],low[maxn],cnt;
void dfs1(int u,int f){
    sz[u]=1;son[u]=0;fa[u]=f;h[u]=h[f]+1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==f)continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[son[u]]<sz[v])son[u]=v;
    }
}
void dfs2(int u,int f,int k){
    top[u]=k;pos[u]=++cnt;
    if(son[u])dfs2(son[u],u,k);
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==f || v==son[u])continue;
        dfs2(v,u,v);
    }
    low[u]=cnt;
}
int LCA(int u,int v){
    while(top[u]!=top[v]){
        if(h[top[u]]<h[top[v]])swap(u,v);
        u=fa[top[u]];
    }
    if(h[u]>h[v])swap(u,v);
    return u; 
}




int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]),t[++vnum]=w[i];
    int u,v,k;
    for(int i=1;i<=n-1;i++){
        scanf("%d %d",&u,&v);
        addedge(u,v);
    }
    for(int i=1;i<=m;i++){
        scanf("%d %d %d",&q[i].k,&q[i].a,&q[i].b);
        if(!q[i].k)t[++vnum]=q[i].b;
    }
    sort(t+1,t+1+vnum);
    vnum=unique(t+1,t+1+vnum)-(t+1);
    for(int i=1;i<=n;i++)w[i]=lower_bound(t+1,t+1+vnum,w[i])-t;
    for(int i=1;i<=m;i++)if(!q[i].k)q[i].b=lower_bound(t+1,t+1+vnum,q[i].b)-t;
    
    
    dfs1(1,0);dfs2(1,0,1);
    
    

    for(int i=1;i<=n;i++)add(pos[i],w[i],1),add(low[i]+1,w[i],-1);
    
    
    
    for(int i=1;i<=m;i++){
        u=q[i].a;v=q[i].b;k=q[i].k;
        if(k){
            int lca=LCA(u,v);
            if(h[u]+h[v]-h[lca]+-h[fa[lca]]<k){
                printf("invalid request!\n");
                continue;
            }
            anum=snum=0;
            for(int i=pos[u];i;i-=lowbit(i))addT[++anum]=T[i];
            for(int i=pos[v];i;i-=lowbit(i))addT[++anum]=T[i];
            for(int i=pos[lca];i;i-=lowbit(i))subT[++snum]=T[i];
            for(int i=pos[fa[lca]];i;i-=lowbit(i))subT[++snum]=T[i];
            printf("%d\n",t[query(1,vnum,k)]);
        }
        else{
            add(pos[u],w[u],-1);add(low[u]+1,w[u],1);
            w[u]=v;
            add(pos[u],w[u],1);add(low[u]+1,w[u],-1);
        }
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!