首页 > 代码库 > bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树

bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树

3545: [ONTAK2010]Peaks

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 635  Solved: 177
[Submit][Status]

Description

在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。

 

Input

第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。

 

Output

对于每组询问,输出一个整数表示答案。

 

Sample Input

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

Sample Output

6
1
-1
8


HINT

 

【数据范围】

N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。

 

  看起来我的数据结构还欠一点火候,加强版在以前做过并查集合并树的基础上还是没有独立想出来。

  非加强版就是离线询问,用并查集套平衡树进行启发式合并。这里平衡树我练习了一下SplitMergeTreap,读入优化卡时过掉了。

  加强版仍是要预处理合并过程,建成并查集的合并树。即并查集合并新建一个节点来表示两个点的并来表示某一合并程度的并查集状态。在已知起点和合并程度时,我们可以快速向父节点搜索找到表示当前状态的点,而所找到的点的子树所有叶子节点都是当前联通块的点。于是我们就可以用主席树维护了。

  有几点注意的,题目需要求一个树所有叶子节点dfs序,不能想当然的把他认为是bfs序什么的,应该用标准的bfs求dfs序的方式写。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAXN 610000#define MAXE 610000#define MAXT MAXN*2#define MAXQ 610000inline int nextInt(){        register char ch;        register int x=0;        while (ch=getchar(),ch<0|| ch>9);        do                x=x*10+ch-0;        while (ch=getchar(),ch<=9 && ch>=0);        return x;}struct Treap{        int ch[MAXT][2];        int key[MAXT],val[MAXT];        int siz[MAXT];        int topt;        inline void update(int now)        {                siz[now]=siz[ch[now][0]]+siz[ch[now][1]]+1;        }        int Merge(int x,int y)        {                if (!x)return y;                if (!y)return x;                if (key[x]<key[y])                {                        ch[x][1]=Merge(ch[x][1],y);                        update(x);                        return x;                }else                 {                        ch[y][0]=Merge(x,ch[y][0]);                        update(y);                        return y;                }        }        pair<int,int> Split(int now,int rk)        {                if (!now)return make_pair(0,0);                if (siz[ch[now][0]]>=rk)                {                        pair<int,int> pr;                        pr=Split(ch[now][0],rk);                        ch[now][0]=0;                        update(now);                        pr.second=Merge(pr.second,now);                        return pr;                }else                {                        pair<int,int> pr;                        pr=Split(ch[now][1],rk-siz[ch[now][0]]-1);                        ch[now][1]=0;                        update(now);                        pr.first=Merge(now,pr.first);                        return pr;                }        }        int Get_rank(int now,int v)        {                if (!now)return 0;                if (val[now]==v)                        return siz[ch[now][0]];                if (v<val[now])                        return Get_rank(ch[now][0],v);                else                        return siz[ch[now][0]]+1+Get_rank(ch[now][1],v);        }        int get_kth(int now,int rk)        {                if (!now)return -1;                if (siz[ch[now][0]]+1==rk)                        return val[now];                if (siz[ch[now][0]]+1<rk)                        return get_kth(ch[now][1],rk-siz[ch[now][0]]-1);                else                        return get_kth(ch[now][0],rk);        }        void Scan(int now)        {                if (!now)return ;                if (siz[now]!=siz[ch[now][0]]+siz[ch[now][1]]+1)throw 1;                Scan(ch[now][0]);                printf("%d ",val[now]);                Scan(ch[now][1]);        }        void Insert(int &root,int v,int now=-1)        {                if (now==-1)now=++topt;                val[now]=v;                key[now]=rand();                siz[now]=1;                ch[now][0]=ch[now][1]=0;                pair<int,int> pr=Split(root,Get_rank(root,v));                root=Merge(pr.first,Merge(now,pr.second));        }        void Comb(int &x,int y)        {                if (!y)return ;                Comb(x,ch[y][0]);                Comb(x,ch[y][1]);                Insert(x,val[y],y);        }}T;int roof[MAXN];int h[MAXN];int n,m,q;struct edge{        int x,y,d;}e[MAXE];bool cmp_edge_d(edge a,edge b){        return a.d<b.d;}struct qur_t{        int c,d,k,id,ans;        qur_t()        {                ans=-1;        }}qur[MAXQ];bool cmp_qur_d(qur_t q1,qur_t q2){        return q1.d<q2.d;}bool cmp_qur_id(qur_t q1,qur_t q2){        return q1.id<q2.id;}int uf[MAXN],ut[MAXN];/*int get_fa(int now){        while (now!=uf[now])        {                ut[uf[now]]=ut[uf[uf[now]]];                uf[now]=uf[uf[now]];        }        return now;}*/pair<int,int> get_fa(int now){        if (now==uf[now])return make_pair(now,ut[now]);        ut[now]=get_fa(uf[now]).second;        uf[now]=get_fa(uf[now]).first;        return make_pair(uf[now],ut[now]);}bool comb(int x,int y){        x=get_fa(x).first;        y=get_fa(y).first;        if (x==y)return false;        if (T.siz[x]>T.siz[y])        {                uf[y]=x;                T.Comb(ut[x],ut[y]);        }else        {                uf[x]=y;                T.Comb(ut[y],ut[x]);        }}int main(){        freopen("input.txt","r",stdin);        int i,j,k,x,y,z;        scanf("%d%d%d",&n,&m,&q);        for (i=1;i<=n;i++)        {                h[i]=nextInt();                //scanf("%d",h+i);                uf[i]=i;                T.Insert(ut[i],h[i]);        }        for (i=0;i<m;i++)        {                e[i].x=nextInt();e[i].y=nextInt();e[i].d=nextInt();                //scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].d);        }        for (i=0;i<q;i++)        {                qur[i].c=nextInt();qur[i].d=nextInt();qur[i].k=nextInt();                //scanf("%d%d%d",&qur[i].c,&qur[i].d,&qur[i].k);                qur[i].id=i;        }        sort(e,e+m,cmp_edge_d);        sort(qur,qur+q,cmp_qur_d);        int nowq=0;        for (i=0;i<m;)        {                x=i;                while (nowq<q && qur[nowq].d<e[x].d)                {                        y=get_fa(qur[nowq].c).first;                        z=T.siz[ut[y]]-qur[nowq].k+1;                        qur[nowq].ans=T.get_kth(ut[y],z);                        nowq++;                }                for (;i<m && e[i].d==e[x].d;i++)                {                //        cout<<"Add:"<<e[i].x<<" "<<e[i].y<<endl;                        comb(e[i].x,e[i].y);                //        cout<<T.siz[ut[get_fa(1).first]]<<endl;                }        }        while (nowq<q)        {                y=get_fa(qur[nowq].c).first;                z=T.siz[ut[y]]-qur[nowq].k+1;                qur[nowq].ans=T.get_kth(ut[y],z);                nowq++;        }        sort(qur,qur+q,cmp_qur_id);        for (i=0;i<q;i++)        {                printf("%d\n",qur[i].ans);        }}
bzoj 3545
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAXN 110000#define MAXM 510000#define MAXV MAXN*2#define MAXE MAXM*2#define MAXT MAXV*4*4#define INF 0x3f3f3f3ftypedef long long qword;const int maxh=1000001000;inline int nextInt(){        char ch;        int x=0;        while (ch=getchar(),ch<0||ch>9);        do                x=x*10+ch-0;        while (ch=getchar(),ch<=9 && ch>=0);        return x;}struct edge{        int x,y,d;}e[MAXE];bool cmp_edge_d(edge e1,edge e2){        return e1.d<e2.d;}int uf[MAXV];int get_fa(int now){        return uf[now]==now?now:uf[now]=get_fa(uf[now]);}bool comb(int x,int y){        x=get_fa(x);        y=get_fa(y);        if (x==y)return 0;        uf[y]=x;        return 1;}struct Edge{        int np;        Edge *next;}E[MAXE],*V[MAXV];int totn;int tope=-1;void addedge(int x,int y){        //cout<<"Add:"<<x<<" "<<y<<endl;        E[++tope].np=y;        E[tope].next=V[x];        V[x]=&E[tope];}int qu[MAXV];int siz[MAXV];int fa[MAXV];int spos[MAXV],tpos[MAXV],apos[MAXV];int n,m,q;void bfs(int now){        int head=-1,tail=0;        Edge *ne;        qu[0]=now;        fa[now]=0;        spos[now]=1;        while (head<tail)        {                now=qu[++head];                for (ne=V[now];ne;ne=ne->next)                {                        fa[ne->np]=now;                        qu[++tail]=ne->np;                }        }        int i,x=0;        for (i=tail;i>=0;i--)        {                now=qu[i];                if (V[now])siz[now]=0;                else siz[now]=1;                for (ne=V[now];ne;ne=ne->next)                {                        siz[now]+=siz[ne->np];                }        }        for (i=0;i<=tail;i++)        {                now=qu[i];                x=spos[now];                if (!V[now])x++;                for (ne=V[now];ne;ne=ne->next)                {                        spos[ne->np]=x;                        x+=siz[ne->np];                }                tpos[now]=x-1;        }        for (i=1;i<=n;i++)                apos[spos[i]]=i;}int h[MAXN];struct sgt_node{        int lc,rc;        int tot;}sgt[MAXT];int tops=0;void Add_sgt(int &now,int base,int l,int r,int pos){        now=++tops;        sgt[now]=sgt[base];        sgt[now].tot++;        if (l==r)return ;        int mid=((qword)l+r)>>1;        if (pos<=mid)                Add_sgt(sgt[now].lc,sgt[base].lc,l,mid,pos);        else                Add_sgt(sgt[now].rc,sgt[base].rc,mid+1,r,pos);}int Qry_sum(int now,int l,int r,int x,int y){        if (!now)                return 0;        if (l==x && r==y)                return sgt[now].tot;        int mid=((qword)l+r)>>1;        if (y<=mid)                return Qry_sum(now,l,mid,x,y);        else if (mid<x)                return Qry_sum(now,mid+1,r,x,y);        else                return Qry_sum(now,l,mid,x,mid)+Qry_sum(now,mid+1,r,mid+1,y);}int Qry_kth(int now1,int now2,int l,int r,int rk){        if (rk<=0)return -1;        if (sgt[now1].tot==sgt[now2].tot)return r;        if (sgt[sgt[now2].lc].tot-sgt[sgt[now1].lc].tot<rk)                return Qry_kth(sgt[now1].rc,sgt[now2].rc,(((qword)l+r)>>1)+1,r,rk-(sgt[sgt[now2].lc].tot-sgt[sgt[now1].lc].tot));        else                return Qry_kth(sgt[now1].lc,sgt[now2].lc,l,((qword)l+r)>>1,rk);}int jump[20][MAXV];void init_lca(){        int i,j;        for (i=1;i<=totn;i++)                jump[0][i]=fa[i];        for (j=1;j<20;j++)                for (i=1;i<=totn;i++)                        jump[j][i]=jump[j-1][jump[j-1][i]];}int root[MAXV];int hmx[MAXV];int main(){//        freopen("input.txt","r",stdin);//        freopen("output.txt","w",stdout);        int i,j,k,x,y,z;        scanf("%d%d%d",&n,&m,&q);        for (i=1;i<=n;i++)                h[i]=nextInt();        for (i=1;i<=n;i++)                uf[i]=i;        totn=n;        for (i=0;i<m;i++)        {                e[i].x=nextInt();                e[i].y=nextInt();                e[i].d=nextInt();        }        sort(e,e+m,cmp_edge_d);        for (i=0;i<m;i++)        {                if (get_fa(e[i].x)==get_fa(e[i].y))continue;                ++totn;                uf[totn]=totn;                hmx[totn]=e[i].d;                addedge(totn,get_fa(e[i].x));                addedge(totn,get_fa(e[i].y));                comb(totn,e[i].x);                comb(totn,e[i].y);        }        ++totn;        uf[totn]=totn;        hmx[totn]=maxh-1;        for (i=1;i<totn;i++)        {                if (get_fa(i)!=totn)                {                        addedge(totn,get_fa(i));                        comb(totn,i);                }        }        bfs(totn);        int last_ans=0;        for (i=1;i<=n;i++)        {                Add_sgt(root[i],root[i-1],-1,maxh,h[apos[i]]);        }        init_lca();        for (i=1;i<=q;i++)        {                scanf("%d%d%d",&x,&y,&z);                if (~last_ans)                {                        x^=last_ans;y^=last_ans;z^=last_ans;                }                for (j=19;j>=0;j--)                {                        if (jump[j][x] && hmx[jump[j][x]]<=y)                                x=jump[j][x];                }                last_ans=Qry_kth(root[spos[x]-1],root[tpos[x]],-1,maxh,sgt[root[tpos[x]]].tot-sgt[root[spos[x]-1]].tot-z+1);                printf("%d\n",(last_ans==-1 || last_ans==maxh)?-1:last_ans);        }}
bzoj 3551

 

bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树