1. 程式人生 > >[CTSC2008] 網路管理

[CTSC2008] 網路管理

Description

帶修樹鏈第K大。\((n,q\leq 80000)\)

Solution

據說有很多種方法? 寫了兩種。

  1. 樹剖套線段樹套平衡樹,外層還需要個二分,複雜度\(O(n\log^4n)\)
  2. \(dfs\)序上維護樹狀陣列套主席樹,複雜度\(O(n\log^2n)\)

第一種就是比較裸的樹套樹吧,注意二分的\(check(x)\)定義是當答案為\(x\)時這條鏈上是否有至少\(k\)個大於\(x\)的點。 然後平衡樹上查就行了。 試了幾個\(srand\)發現我的生日加上xxx的生日跑的最快... 第二種就可以說一說了 先考慮無修改樹鏈第\(k\)大怎麼求,顯然每個點的主席樹存下了這個點到根的路徑上所有點的權值。然後就是\(sum[x]+sum[y]-sum[lca(x,y)]-sum[fa[lca(x,y)]]\)

。 如果有修改,那麼改一個點時會影響到子樹內的\(O(n)\)棵主席樹。 但是觀察到一個點的子樹的\(dfs\)序是一段區間,可以區間加這個玩意兒。 然而區間主席樹加某個值並不好加,我們可以在差分序列上變成單點加。然後求和的時候求一個字首和就行了。具體地,我們可以把求這四個點(\(x,y,lca(x,y),fa[lca(x,y)]\))的字首和所需要用到的點都存進一個數組裡面,然後主席樹求\(k\)大的時候就不是四個點同時往下走而是這個數組裡面所有的點同時往下走了。 然後要記得輸出原本的值不要輸出離散化之後的值。。。 別的就沒啥了,發現自己已經zz到看一個單點加都要思考半天為什麼要用樹狀陣列了。。。。

Code

\(O(n\log^4n)\)程式碼 這奇怪的變數名奇怪的函式名和奇怪的縮排是我想寫namespace無果造成的,我的碼風還是正常的你們要相信我啊喂

#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
const int N=80005;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define mp(A,B) std::make_pair(A,B)

int root[N<<2];
int head[N],dfn[N],val[N];
int n,m,cnt,fa[N],d[N],tot;
int top[N],sze[N],son[N],fs[N];

struct Edge{
    int to,nxt;
}edge[N<<1];

void add(int x,int y){
    edge[++cnt].to=y;
    edge[cnt].nxt=head[x];
    head[x]=cnt;
}

    int ttot;
    int delpool[N*20],delcur;
    int tsze[N*20],tprio[N*20];
    int tch[N*20][2],tval[N*20];

    void tpushup(int cur){
        tsze[cur]=tsze[tch[cur][0]]+tsze[tch[cur][1]]+1;
    }

    void trotate(int &x,int d){
        int y=tch[x][d],z=tch[y][d^1];
        tch[y][d^1]=x;tch[x][d]=z;
        tpushup(x);tpushup(y);x=y;
    }

    int newnode(){
        int t=delcur?delpool[delcur--]:++ttot;
        tch[t][0]=tch[t][1]=tval[t]=tprio[t]=tsze[t]=0;return t;
    }

    void tinsert(int &cur,int x){
        if(!cur){
            cur=newnode();
            tsze[cur]=1;tval[cur]=x;tprio[cur]=rand();
            return;
        }
        int d=x>tval[cur];
        tsze[cur]++;
        tinsert(tch[cur][d],x);
        if(tprio[tch[cur][d]]<tprio[cur])
            trotate(cur,d);
    }

    void tremove(int &cur,int x){
        if(tval[cur]==x){
            if(!tch[cur][0] or !tch[cur][1]){
                delpool[++delcur]=cur;
                cur=tch[cur][0]+tch[cur][1];
                return;
            }
            if(tprio[tch[cur][0]]<tprio[tch[cur][1]])
                trotate(cur,0),tremove(tch[cur][1],x);
            else trotate(cur,1),tremove(tch[cur][0],x);
            tpushup(cur);
        } else{
            int d=x>tval[cur];
            tremove(tch[cur][d],x);
            tpushup(cur);
        }
    }

    int trank(int cur,int x){
        if(!cur) return 0;
        if(tval[cur]>=x) return tsze[tch[cur][1]]+1+trank(tch[cur][0],x);
        else return trank(tch[cur][1],x);
    }

    void dfs(int x,int y){
        if(!x) return;
        tinsert(root[y],tval[x]);
        dfs(tch[x][0],y);
        dfs(tch[x][1],y);
    }

    void build(int cur,int l,int r){
        if(l==r){
            tinsert(root[cur],val[fs[l]]);
            return;
        }
        int mid=l+r>>1;
        build(cur<<1,l,mid);build(cur<<1|1,mid+1,r);
        dfs(root[cur<<1],cur);dfs(root[cur<<1|1],cur);
    }

    void modify(int cur,int l,int r,int ql,int qr,int minus,int add){
        tremove(root[cur],minus);tinsert(root[cur],add);
        if(l==r) return;
        int mid=l+r>>1;
        if(ql<=mid) modify(cur<<1,l,mid,ql,qr,minus,add);
        else modify(cur<<1|1,mid+1,r,ql,qr,minus,add);
    }

    int query(int cur,int l,int r,int ql,int qr,int c){
        if(ql<=l and r<=qr)
            return trank(root[cur],c);
        int mid=l+r>>1,ans=0;
        if(ql<=mid) ans+=query(cur<<1,l,mid,ql,qr,c);
        if(mid<qr) ans+=query(cur<<1|1,mid+1,r,ql,qr,c);
        return ans;
    }

int getint(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while( isdigit(ch))X=X*10+ch-48,ch=getchar();
    return w?-X:X;
}

void dfs1(int now){
    sze[now]=1;
    for(int i=head[now];i;i=edge[i].nxt){
        int to=edge[i].to;
        if(sze[to]) continue;
        fa[to]=now;d[to]=d[now]+1;
        dfs1(to);sze[now]+=sze[to];
        son[now]=sze[to]>sze[son[now]]?to:son[now];
    }
}

void dfs2(int now,int low){
    dfn[now]=++tot;top[now]=low;fs[tot]=now;
    if(son[now]) dfs2(son[now],low);
    for(int i=head[now];i;i=edge[i].nxt){
        int to=edge[i].to;
        if(dfn[to]) continue;
        dfs2(to,to);
    }
}

bool check(int mid,int k,int x,int y){
    int ans=0,fir=d[x]+d[y];
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]])
            swap(x,y);
        ans+=query(1,1,n,dfn[top[x]],dfn[x],mid);
        x=fa[top[x]];
    }
    if(d[x]<d[y]) swap(x,y);
    ans+=query(1,1,n,dfn[y],dfn[x],mid);
    fir-=d[y]*2;fir++;
    if(fir<k) return 0;
    if(ans>=k) return 1;
    return 0;
}

signed main(){
    srand(20020122);
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)
        val[i]=getint();
    for(int i=1;i<n;i++){
        int x=getint(),y=getint();
        add(x,y);add(y,x);
    }
    d[1]=1;dfs1(1);dfs2(1,1);build(1,1,n);
    while(m--){
        int k=getint(),x=getint(),y=getint();
        if(!k){
            modify(1,1,n,dfn[x],dfn[x],val[x],y);
            val[x]=y;
        } else{
            int l=0,r=1e8,ans=1e8;
            while(l<=r){
                int mid=l+r>>1;
                if(check(mid,k,x,y)) ans=mid,l=mid+1;
                else r=mid-1;
            } printf(ans==1e8?"invalid request!\n":"%d\n",ans);
        }
    } return 0;
}

然後是\(O(n\log^2n)\)

#include<cctype>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
const int N=80005;
typedef double db;
typedef long long ll;
const int M=10000010;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define mp(A,B) std::make_pair(A,B)

int s1[N<<1],s2[N<<1];
int n,m,cnt,tot,val[N],sze[N];
int k[N],x[N],y[N],g[N<<1],len;
int ch[M][2],root[N],f[N][19];
int head[N],sum[M],dfn[N],d[N];

struct Edge{
    int to,nxt;
}edge[N<<1];

void add(int x,int y){
    edge[++cnt].to=y;
    edge[cnt].nxt=head[x];
    head[x]=cnt;
}

int getint(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while( isdigit(ch))X=X*10+ch-48,ch=getchar();
    return w?-X:X;
}

void dfs(int now){
    sze[now]=1;dfn[now]=++tot;
    for(int i=head[now];i;i=edge[i].nxt){
        int to=edge[i].to;
        if(sze[to]) continue;
        f[to][0]=now;d[to]=d[now]+1;
        for(int j=1;j<=17;j++) f[to][j]=f[f[to][j-1]][j-1];
        dfs(to);sze[now]+=sze[to];
    }
}

void pushup(int cur){
    sum[cur]=sum[ch[cur][0]]+sum[ch[cur][1]];
}

void modify(int &cur,int ql,int c,int l=1,int r=len){
    if(!cur) cur=++tot;
    if(l==r){sum[cur]+=c;return;}
    int mid=l+r>>1;
    if(ql<=mid) modify(ch[cur][0],ql,c,l,mid);
    else modify(ch[cur][1],ql,c,mid+1,r);
    pushup(cur);
}

void add(int x,int y,int z){
    while(x<=n)
        modify(root[x],y,z),x+=x&-x;
}

int lca(int x,int y){
    if(d[x]<d[y]) swap(x,y);
    for(int i=17;~i;i--)
        if(d[f[x][i]]>=d[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=17;~i;i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}

int query(int k,int l=1,int r=len){
    if(l==r) return l;
    int now=0,mid=l+r>>1;
    for(int i=1;i<=s1[0];i++) now+=sum[ch[s1[i]][1]];
    for(int i=1;i<=s2[0];i++) now-=sum[ch[s2[i]][1]];
    if(now>=k){
        for(int i=1;i<=s1[0];i++) s1[i]=ch[s1[i]][1];
        for(int i=1;i<=s2[0];i++) s2[i]=ch[s2[i]][1];
        return query(k,mid+1,r);
    } else{
        for(int i=1;i<=s1[0];i++) s1[i]=ch[s1[i]][0];
        for(int i=1;i<=s2[0];i++) s2[i]=ch[s2[i]][0];
        return query(k-now,l,mid);
    }
}

void ask(int k,int a,int b){
    int c=lca(a,b),dd=f[c][0];s1[0]=s2[0]=0;
    if(d[a]+d[b]-d[c]-d[dd]<k) {printf("invalid request!\n");return;}
    for(int i=dfn[a];i;i-=i&-i) s1[++s1[0]]=root[i];
    for(int i=dfn[b];i;i-=i&-i) s1[++s1[0]]=root[i];
    for(int i=dfn[c];i;i-=i&-i) s2[++s2[0]]=root[i];
    for(int i=dfn[dd];i;i-=i&-i) s2[++s2[0]]=root[i];
    printf("%d\n",g[query(k)]);
}

signed main(){
    n=getint(),m=getint();
    for(int i=1;i<=n;i++) val[i]=getint(),g[++len]=val[i];
    for(int i=1;i<n;i++){
        int x=getint(),y=getint();
        add(x,y);add(y,x);
    }
    for(int i=1;i<=m;i++){
        k[i]=getint(),x[i]=getint(),y[i]=getint();
        if(!k[i]) g[++len]=y[i];
    }
    std::sort(g+1,g+1+len);len=std::unique(g+1,g+1+len)-g-1;
    for(int i=1;i<=n;i++) val[i]=std::lower_bound(g+1,g+1+len,val[i])-g;
    for(int i=1;i<=m;i++) if(!k[i]) y[i]=std::lower_bound(g+1,g+1+len,y[i])-g;
    d[1]=1;dfs(1);tot=0;
    for(int i=1;i<=n;i++) add(dfn[i],val[i],1),add(dfn[i]+sze[i],val[i],-1);
    for(int i=1;i<=m;i++){
        if(!k[i]) add(dfn[x[i]],val[x[i]],-1),add(dfn[x[i]]+sze[x[i]],val[x[i]],1),val[x[i]]=y[i],add(dfn[x[i]],val[x[i]],1),add(dfn[x[i]]+sze[x[i]],val[x[i]],-1);
        else ask(k[i],x[i],y[i]);
    } return 0;
}