把所有询问离线下来,从小到大枚举边合并,用并查集维护连通块,每块维护一个平衡树,合并时启发式合并。
一开始写的是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;
}