[BZOJ 3551+3545]Peaks

加强:题目传送-BZOJ3551

原味:题目传送-BZOJ3545

题意:

有一个\(n\)个点\(m\)条边的无向图,点有点权,边有边权。
\(q\)次询问(u,val,k)
表示从\(u\)出发,经过的边权都小于等于\(val\),能到达的所有点中,点权第\(k\)大的权值
强制在线
$n \le 100000,m \le 500000,q \le 300000 $

题解:

做过NOI2018D1T1的再做这题就思路清晰了
你需要先学会Kruskal重构树,也不是什么高大上的东西..
然后这就变成了一棵树,按DFS序将叶子节点映射到一个序列上
转换为区间第K大,就随便做了..我用的是主席树

过程:

先忘了强制在线,再各种细节..

代码:

const int N=100010,M=500010,lgN=18,ALL=N<<1;
int n,m,q,rt,all;
int h[N];
int head[ALL],nxt[ALL],to[ALL],lst=0;
int bd[ALL],fa[ALL];
inline void adde(int x,int y) {
    assert(fa[y]==x);
    nxt[++lst]=head[x]; to[lst]=y; head[x]=lst;
}
namespace KRU {
    struct EDGE {
        int x,y,c;
        inline void in() {
            read(x); read(y); read(c);
        }
        bool operator < (const EDGE &a)const {
            return c<a.c;
        }
    }e[M];
    int fat[N],ref[N],ind=0;
    int father(int x) {return x==fat[x] ? x : fat[x]=father(fat[x]);}
    inline int Kruskal() {
        sort(e+1,e+m+1); int k=0; ind=n;
        for(int i=1;i<=n;i++) fat[i]=ref[i]=i;
        for(int i=1;i<=m;i++) {
            int fx=father(e[i].x),fy=father(e[i].y);
            if(fx!=fy) {
                int np=++ind; fa[ref[fy]]=fa[ref[fx]]=np;
                adde(np,ref[fy]); adde(np,ref[fx]); bd[np]=e[i].c;
                ref[fy]=np; ref[fx]=0; fat[fx]=fy;
                if(++k==n-1) return ind;
            }
        }
        int np=++ind; bd[np]=INF;
        for(int i=1;i<=n;i++)
            if(father(i)==i) {
                fa[ref[i]]=np;
                adde(np,ref[i]);
            }
        // printf("lst=%d\n",lst);
        return ind;
    }
}
int le[ALL],t_s[ALL],s_t[ALL],ind=0;
namespace TREE {
    int anc[ALL][lgN+2],lim[ALL][lgN+2],dep[ALL],sz[ALL];
    void Print(int u) {
        for(int i=1;i<dep[u];i++) putchar('\t'); printf("%d:%d %d\n",u,fa[u],bd[u]);
        for(int i=head[u];i;i=nxt[i]) Print(to[i]);
    }
    int cnt;
    void Build(int u) {
        // printf("%d\n",u);
        bool fl=0; sz[u]=0; ++cnt;
        for(int i=head[u];i;i=nxt[i]) {
            int v=to[i]; assert(v!=fa[u]);
            dep[v]=dep[u]+1;
            anc[v][0]=u;
            lim[v][0]=bd[u];
            Build(v);
            if(!fl) le[u]=le[v];
            sz[u]+=sz[v];
            fl=1;
        }
        if(!fl) assert(u<=n);
        if(u<=n) assert(!fl);
        if(!fl) {le[u]=u; t_s[u]=++ind; s_t[ind]=u; sz[u]=1;}
    }
    inline void Init(int rt) {
        lim[rt][0]=INF; dep[rt]=1;//ATT
        mem(lim,63);
        Build(rt); assert(cnt==all); assert(ind==n);
        for(int j=1;j<=lgN;j++)
            for(int i=1;i<=all;i++) {
                anc[i][j]=anc[anc[i][j-1]][j-1];
                lim[i][j]=lim[anc[i][j-1]][j-1];
            }
    }
    inline int Find(int u,int v) {
        for(int i=lgN;i>=0;i--) if(lim[u][i]<=v) u=anc[u][i];
        return u;
    }
}
namespace SEG {
    #define lc ch[u][0]
    #define rc ch[u][1]
    #define left lc,l,mid
    #define right rc,mid+1,r
    #define mid ((l+r)>>1)
    const int U=N*lgN;
    int rt[ALL],sz[U],ch[U][2],ind=1;
    inline int New_Node(int u) {
        sz[++ind]=sz[u];
        ch[ind][0]=ch[u][0]; ch[ind][1]=ch[u][1];
        return ind;
    }
    void Modify(int &u,int l,int r,int x) {
        // printf("%d %d %d %d\n",u,l,r,x);
        u=New_Node(u);
        if(l==r) {
            if(l!=x) cerr<<x<<endl;
            assert(l==x);
            ++sz[u]; return;
        }
        if(x<=mid) Modify(left,x);
        if(x> mid) Modify(right,x);
        sz[u]=sz[lc]+sz[rc];
    }
    int Query(int u1,int u2,int l,int r,int k) {
        if(l==r) return l;
        int szl=sz[ch[u2][0]]-sz[ch[u1][0]];
        // printf("%d %d %d %d %d\n",u1,u2,szl,l,r);
        if(szl<k) return Query(ch[u1][1],ch[u2][1],mid+1,r,k-szl);
        else return Query(ch[u1][0],ch[u2][0],l,mid,k);
    }
    inline void Init() {
        for(int i=1;i<=n;i++) {
            rt[i]=rt[i-1];
            // printf("%d\n",s_t[i]);
            Modify(rt[i],1,n,h[s_t[i]]);
            // printf("%d\n",sz[rt[i]]);
        }
        // printf("rt\n"); for(int i=1;i<=n;i++) printf("%d ",rt[i]); puts("");
    }
}
map<int,int> key;
int _key[N];
int num[N],tot;
signed main() {
    // freopen("4.in","r",stdin);
    // freopen("my.out","w",stdout);
    read(n); read(m); read(q); tot=n;
    for(int i=1;i<=n;i++) read(h[i]),num[i]=h[i];
    sort(num+1,num+n+1); tot=unique(num+1,num+tot+1)-num-1;
    for(int i=tot;i>=1;i--) key[num[i]]=tot-i+1,_key[tot-i+1]=num[i];//reverse
    for(int i=1;i<=n;i++) h[i]=key[h[i]],assert(h[i]!=0);
    for(int i=1;i<=m;i++) KRU::e[i].in();
    
    all=rt=KRU::Kruskal(); TREE::Init(rt); SEG::Init();
    int ans=0;
    while(q--) {
        int u,v,k; read(u); read(v); read(k);
        u^=ans; v^=ans; k^=ans;
        u=TREE::Find(u,v); 
        // cerr<<'u'<<u<<"BD::"<<TREE::lim[u][0]<<" "<<v<<endl;
        if(TREE::sz[u]<k) ans=0,puts("-1");
        else {
            ans=SEG::Query(SEG::rt[t_s[le[u]]-1],SEG::rt[t_s[le[u]]+TREE::sz[u]-1],1,n,k);
            printf("%d\n",ans=_key[ans]);
        }
    }
    return 0;
}
/*
10 11 4
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2
*/

用时:1.5h

猜你喜欢

转载自www.cnblogs.com/functionendless/p/9498283.html