Luogu_4197 Peaks

P4197 Peaks

并不会克鲁斯卡尔重构树,于是就写了离线算法。

使用了最小生成树,启发式合并treap

在最小生成树,克鲁斯卡尔算法 时 ,将询问一块处理。便可以保证询问时边的要求。然后利用平衡树,加速计算。

// luogu-judger-enable-o2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <ctime>

#define Ls T[R].ch[0]
#define Rs T[R].ch[1]
#define T_d T[R].ch[d]

using std::sort;

const int maxn=201000;
const int inf=0x7fffffff;

struct Tree
{
    int val;
    int key;
    int Size;
    int Self;
    int ch[2];
    Tree(int a=0,int b=1,int c=1)
    {
        key=rand();
        val=a;
        Size=b;
        Self=c;
        ch[0]=ch[1]=0;
    }
    void Clear()
    {
        Size=Self;
        ch[0]=ch[1]=0;
    }
};

struct Data
{
    int A,B;
    int Value,Tag;
    int Num;
    Data (int a=0,int b=0,int v=0,int t=-inf,int n=0)
    {
        A=a;B=b;
        Value=v;
        Tag=t;
        Num=n;
    }
};

Tree T[maxn];
Data base[maxn*5];
int h[maxn],f[maxn],tail;
int belong[maxn],ans[maxn*5];

int Find(int x)
{
    if(f[x]==x) return f[x];
    return f[x]=Find(f[x]);
}

int compare(const Data &a,const Data &b)
{
    if(a.Value!=b.Value)    return a.Value<b.Value;
    return a.Tag<b.Tag;
}

int cmpkth(int R,int kth)
{
    int s=T[Rs].Size;
    if(kth<=s)  return 1;
    if(kth>s+T[R].Self) return 0;
    return -1;
}

int cmpval(int R,int val)
{
    if(T[R].val==val)   return -1;
    return T[R].val<val;
}

void  Sum(int R)
{
    T[R].Size=T[R].Self+T[Ls].Size+T[Rs].Size;
    return ;
}

void Rotate(int &R,int dir)
{
    int k=T[R].ch[dir^1];
    T[R].ch[dir^1]=T[k].ch[dir];
    T[k].ch[dir]=R;
    Sum(R);Sum(k);
    R=k;
}

int Seek_kth(int R,int kth)
{
    int d=cmpkth(R,kth);
    if(d==-1)   return T[R].val;
    return Seek_kth(T_d,kth-=( d==0 ? T[Rs].Size+T[R].Self : 0 ));
}

void Insert(int &R,int val,int model=0,int num=0)
{
    if(R==0)
    {
        if(model==0){   R=++tail;T[R]=Tree(val); }
        else    {   T[num].Clear();R=num; }
        return ;
    }
    int d=cmpval(R,val);
    if(d==-1)
    {
        int add=( model ? T[num].Self : 1 );
        T[R].Self+=add;
        T[R].Size+=add;
        return ;
    }
    Insert(T_d,val,model,num);
    Sum(R);
    if(T[T_d].key>T[R].key) Rotate(R,d^1);
    return ;
}

void _merge(int &R,int &Dir)
{
    if(R==0)    return ;
    _merge(Ls,Dir);
    _merge(Rs,Dir);
    Insert(Dir,T[R].val,1,R);
    return ;
}

void Merge(int &A,int &B,int f1,int f2)
{
    if(T[A].Size>T[B].Size)
    {
        _merge(B,A);
        f[f2]=f1;
        B=A;
        return ;
    }
    else
    {
        _merge(A,B);
        f[f1]=f2;
        A=B;
        return ;
    }
}

void visit(int now)
{
    if(now==0)  return ;
    visit(T[now].ch[0]);
    printf("%d ",T[now].val);
    visit(T[now].ch[1]);
}

int main()
{
    srand(time(NULL));
    int n,m,q;
    T[0].Self=0;T[0].Size=0;
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)
        scanf("%d",&h[i]),f[i]=i;
    for(int i=1;i<=n;i++)
        Insert(belong[i],h[i]);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        base[i]=Data(a,b,c);
    }
    for(int i=1;i<=q;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        base[i+m]=Data(a,c,b,0,i);
        ans[i]=-1;
    }
    sort(base+1,base+1+m+q,compare);
    for(int i=1;i<=m+q;i++)
    {
        if(base[i].Tag==0)
        {
            int _f=Find(base[i].A);
            if(T[belong[_f]].Size>=base[i].B)
                ans[base[i].Num]=Seek_kth(belong[_f],base[i].B);
        }
        else
        {
            int f1=Find(base[i].A),f2=Find(base[i].B);
            if(f1==f2)  continue;
            Merge(belong[f1],belong[f2],f1,f2);
        }
    }
    for(int i=1;i<=q;i++)
        printf("%d\n",ans[i]);
//    return 0;
    return 0;
}

posted @ 2019-01-29 00:17  Lance1ot  阅读(89)  评论(0编辑  收藏