bzoj 3545 [ONTAK2010]Peaks 平衡树启发式合并

把所有询问离线下来,从小到大枚举边合并,用并查集维护连通块,每块维护一个平衡树,合并时启发式合并。
一开始写的是splay找前驱后继然后插入TLE,改成插到叶子上才过。不过在官网还是T的。splay常数果然大。。。
这题读入太大,要用读入优化。。。

插入时插成叶子:

#include <bits/stdc++.h>
using namespace std;
#define N 110000
#define M 510000
#define inf 2e9
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define which(x) (ch[fa[x]][1]==x)
int n,m,Q,cnt,l,r;
int v[M],a[M],b[M],c[M],p1[M],root[N];
int beg[M],lim[M],K[M],p2[M],fat[N],ans[M];
int fa[M],ch[M][2],size[M];
int cmp1(int x,int y){return c[x]<c[y];}
int cmp2(int x,int y){return lim[x]<lim[y];}
int find(int x){return fat[x]==x ? x:fat[x]=find(fat[x]);}
void pushup(int x)
{size[x]=size[ls(x)]+size[rs(x)]+1;}
void rotate(int x)
{
    int y=fa[x],k=which(x);
    ch[y][k]=ch[x][k^1];
    ch[x][k^1]=y;
    ch[fa[y]][which(y)]=x;
    fa[x]=fa[y];fa[y]=x;
    fa[ch[y][k]]=y;
    pushup(y);pushup(x);
}
void splay(int x,int tar,int &rt)
{
    while(fa[x]!=tar)
    {
        int y=fa[x];
        if(fa[y]==tar)rotate(x);
        else
        {
            if(which(x)^which(y))
                rotate(x);
            else rotate(y);
            rotate(x);
        }
    }
    if(!tar)rt=x;
}
void insert(int x,int &y)
{
    if(!y)
    {
        ch[x][0]=ch[x][1]=0;
        y=x;size[x]=1;
        return;
    }
    if(v[x]<v[y])
    {
        insert(x,ch[y][0]);
        fa[ch[y][0]]=y;pushup(y);
    }
    else
    {
        insert(x,ch[y][1]);
        fa[ch[y][1]]=y;pushup(y);
    }
}
void dfs(int x,int y)
{
    if(!x)return;
    dfs(ls(x),y);dfs(rs(x),y);
    if(x<=n)
    {
        insert(x,root[y]);
        splay(x,root[y],root[y]);
    }
}
int findk(int x,int K)
{
    if(size[rs(x)]+1==K)return x;
    if(size[rs(x)]>=K)return findk(rs(x),K);
    return findk(ls(x),K-size[rs(x)]-1);
}
char getc()
{
    static const int LEN = 4096;
    static char buf[LEN],*S=buf,*T=buf;
    if(S == T)
    {
        T = (S=buf)+fread(buf,1,LEN,stdin);
        if(S == T)return EOF;
    }
    return *S++;
}
int read()
{
    static char ch;
    static int D;
    while(!isdigit(ch=getc()));
    for(D=ch-'0'; isdigit(ch=getc());)
        D=(D<<3)+(D<<1)+(ch-'0');
    return D;
}
int main()
{
    n=read();m=read();Q=read();
    for(int i=1;i<=n;i++)v[i]=read();
    for(int i=1;i<=m;i++)
        a[i]=read(),b[i]=read(),c[i]=read(),p1[i]=i;
    sort(p1+1,p1+1+m,cmp1);
    for(int i=1;i<=Q;i++)
        beg[i]=read(),lim[i]=read(),K[i]=read(),p2[i]=i;
    sort(p2+1,p2+1+Q,cmp2);
    cnt=n;
    for(int i=1;i<=n;i++)
        fat[i]=i,size[i]=1,root[i]=i;
    for(int i=1,now=1,t;i<=Q;i++)
    {
        while(now<=m&&c[t=p1[now]]<=lim[p2[i]])
        {
            int x=find(a[t]),y=find(b[t]);
            if(x!=y)
            {
                if(size[root[x]]<size[root[y]])
                    swap(x,y);
                fat[y]=x;dfs(root[y],x);
            }
            now++;
        }
        int x=find(beg[p2[i]]);
        if(size[root[x]]<K[p2[i]])ans[p2[i]]=-1;
        else ans[p2[i]]=findk(root[x],K[p2[i]]);
    }
    for(int i=1;i<=Q;i++)
    {
        if(ans[i]==-1)puts("-1");
        else printf("%d\n",v[ans[i]]);
    }
    return 0;
}

插入时找前驱后继(TLE):

#include <bits/stdc++.h>
using namespace std;
#define N 1100000
#define M 1100000
#define inf 2e9
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define which(x) (ch[fa[x]][1]==x)
int n,m,Q,cnt,l,r;
int v[N],a[M],b[M],c[M],p1[M],root[N];
int beg[M],lim[M],K[M],p2[M],fat[N],ans[M];
int fa[M],ch[M][2],size[M],L[N],R[N];
int cmp1(int x,int y){return c[x]<c[y];}
int cmp2(int x,int y){return lim[x]<lim[y];}
int find(int x){return fat[x]==x ? x:fat[x]=find(fat[x]);}
int dcmp(int x,int y)
{
    if(v[x]==v[y])return x>y ? 1:-1;
    return v[x]>v[y] ? 1:-1;
}
void findl(int x,int y)
{
    if(!x)return;
    if(dcmp(x,y)<0)
    {
        if(dcmp(x,l)>0)l=x;
        findl(ch[x][1],y);
    }
    else findl(ch[x][0],y);
}
void findr(int x,int y)
{
    if(!x)return;
    if(dcmp(x,y)>0)
    {
        if(dcmp(x,r)<0)r=x;
        findr(ch[x][0],y);
    }
    else findr(ch[x][1],y);
}
void pushup(int x)
{size[x]=size[ls(x)]+size[rs(x)]+1;}
void rotate(int x)
{
    int y=fa[x],k=which(x);
    ch[y][k]=ch[x][k^1];
    ch[x][k^1]=y;
    ch[fa[y]][which(y)]=x;
    fa[x]=fa[y];fa[y]=x;
    fa[ch[y][k]]=y;
    pushup(y);pushup(x);
}
void splay(int x,int tar,int &rt)
{
    while(fa[x]!=tar)
    {
        int y=fa[x];
        if(fa[y]==tar)rotate(x);
        else
        {
            if(which(x)^which(y))
                rotate(x);
            else rotate(y);
            rotate(x);
        }
    }
    if(!tar)rt=x;
}
void insert(int x,int y)
{
    int &rt=root[y];
    l=L[y];r=R[y];
    findl(rt,x);findr(rt,x);
    splay(l,0,rt);splay(r,l,rt);
    ch[r][0]=x;fa[x]=r;
    size[r]++;size[l]++;
    size[x]=1;ls(x)=rs(x)=0;
}
void dfs(int x,int y)
{
    if(!x)return;
    dfs(ls(x),y);dfs(rs(x),y);
    if(x<=n)insert(x,y);
}
int findk(int x,int K)
{
    if(size[rs(x)]+1==K)return x;
    if(size[rs(x)]>=K)return findk(rs(x),K);
    return findk(ls(x),K-size[rs(x)]-1);
}
char getc()
{
    static const int LEN = 4096;
    static char buf[LEN],*S=buf,*T=buf;
    if(S == T)
    {
        T = (S=buf)+fread(buf,1,LEN,stdin);
        if(S == T)return EOF;
    }
    return *S++;
}
int read()
{
    static char ch;
    static int D;
    while(!isdigit(ch=getc()));
    for(D=ch-'0'; isdigit(ch=getc());)
        D=(D<<3)+(D<<1)+(ch-'0');
    return D;
}
int main()
{
    //freopen("tt.in","r",stdin);
    n=read();m=read();Q=read();
    for(int i=1;i<=n;i++)v[i]=read();
    for(int i=1;i<=m;i++)
        a[i]=read(),b[i]=read(),c[i]=read(),p1[i]=i;
    sort(p1+1,p1+1+m,cmp1);
    for(int i=1;i<=Q;i++)
        beg[i]=read(),lim[i]=read(),K[i]=read(),p2[i]=i;
    sort(p2+1,p2+1+Q,cmp2);
    cnt=n;
    for(int i=1;i<=n;i++)
    {
        fat[i]=i,size[i]=3,root[i]=i;
        ls(i)=++cnt;rs(i)=++cnt;
        fa[ls(i)]=fa[rs(i)]=i;
        size[ls(i)]=size[rs(i)]=1;
        L[i]=ls(i);R[i]=rs(i);
        v[ls(i)]=-inf;v[rs(i)]=inf;
    }
    for(int i=1,now=1,t;i<=Q;i++)
    {
        while(now<=m&&c[t=p1[now]]<=lim[p2[i]])
        {
            int x=find(a[t]),y=find(b[t]);
            if(x!=y)
            {
                if(size[root[x]]<size[root[y]])
                    swap(x,y);
                fat[y]=x;dfs(root[y],x);
            }
            now++;
        }
        int x=find(beg[p2[i]]);
        if(size[root[x]]-2<K[p2[i]])ans[p2[i]]=-1;
        else ans[p2[i]]=findk(root[x],K[p2[i]]+1);
    }
    for(int i=1;i<=Q;i++)
    {
        if(ans[i]==-1)puts("-1");
        else printf("%d\n",v[ans[i]]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值