【纪念】我写过几乎最长的代码
题意
题解
数据结构分析题.
首先观察到有两个维度的信息, 领导力和年龄
对于每个询问, x y, 我们需要知道的是谁来当领导, 暴力枚举可以拿到一些暴力分
注意到领导的领导能力必须要大于等于这两个人中的较大值.
这里凭借直觉我们可以大概感受到应该按照领导能力从大到小去离线处理每一个询问,在回答当前问题前应该将所有的领导力比当前询问大的信息都考虑了
在这个前提下我们就不需要关心领导力这一维信息了, 只需要专注于年龄这一维.
由于年龄的限制是一个区间, 那么问题转换为求一个区间内选谁当领导小组人数最多, 所以如果预处理出每个人当领导的时候这个组最多有多少人, 问题就转换成简单的线段树求区间最值
目前做过几乎最难的线段树。。。
数据范围大,要离散化。
多组询问,要离线。
离散化之后找覆盖的区间,需要二分。
需要预处理,总共开两颗线段树。
还有种种繁多的细节。。。
代码将近 \(200\) 行的线段树,头一次写,调傻了。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define FCC fclose(stdin),fclose(stdout)
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1)
const int INF = 0x3f3f3f3f,N = 2e5+10;
inline ll read()
{
ll ret=0;char ch=' ',c=getchar();
while(!(c>='0'&&c<='9')) ch=c,c=getchar();
while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
return ch=='-'?-ret:ret;
}
int n,k,tot;
int rnk[N],p[N],old[N],val[N];
int res[N];
int qu;
struct node
{
int rep,age,id;
bool operator <(const node &oth) const
{return rep>oth.rep;}
}a[N];
struct ask
{
int x,y,id;
bool operator <(const ask &oth) const
{return a[rnk[y]].rep>a[rnk[oth.y]].rep;}
}q[N];
struct Segtree
{
int mx[N<<2];
ll sum[N<<2];
void init()
{
memset(mx,0,sizeof(mx));
memset(sum,0,sizeof(sum));
}
void modify(int k,int l,int r,int x,int v)
{
if(l==r) {sum[k]+=v,mx[k]=max(mx[k],v);return;}
if(x<=mid) modify(ls,l,mid,x,v);
else modify(rs,mid+1,r,x,v);
mx[k]=max(mx[ls],mx[rs]);
sum[k]=sum[ls]+sum[rs];
}
int query_max(int k,int l,int r,int x,int y)
{
if(x<=l&&r<=y) return mx[k];
int ret=0;
if(x<=mid) ret=max(ret,query_max(ls,l,mid,x,y));
if(y>mid) ret=max(ret,query_max(rs,mid+1,r,x,y));
return ret;
}
int query_sum(int k,int l,int r,int x,int y)
{
if(x<=l&&r<=y) return sum[k];
int ret=0;
if(x<=mid) ret+=query_sum(ls,l,mid,x,y);
if(y>mid) ret+=query_sum(rs,mid+1,r,x,y);
return ret;
}
}str1,str2;
void discrete()
{
for(int i=1;i<=n;i++) p[i]=a[i].age;
sort(p+1,p+n+1);
tot=unique(p+1,p+n+1)-p-1;
/*
printf("before\nid:");
for(int i=1;i<=n;i++) printf("%d ",a[i].id);
printf("\nrep:");
for(int i=1;i<=n;i++) printf("%d ",a[i].rep);
printf("\nage:");
for(int i=1;i<=n;i++) printf("%d ",a[i].age);
printf("\n");
*/
for(int i=1;i<=n;i++)
{
int tmp=lower_bound(p+1,p+tot+1,a[i].age)-p;
old[tmp]=a[i].age;
a[i].age=tmp;
}
/*
printf("after\n");
for(int i=1;i<=n;i++) printf("%d ",a[i].age);
printf("\n");
*/
return;
}
inline int find(int x,int op)
{
if(!op)
{
int l=1,r=x;
while(l<r)
{
int Mid=(l+r)>>1;
if(old[Mid]<old[x]-k) l=Mid+1;
else r=Mid;
}
return l;
}
else
{
int l=x,r=tot;
while(l<r)
{
int Mid=(l+r+1)>>1;
if(old[Mid]>old[x]+k) r=Mid-1;
else l=Mid;
}
return l;
}
}
void pre()
{
int pl=n;
for(int i=n;i>=1;i--)
{
int pos=a[i].age;
while(pl>=1&&a[pl].rep<=a[i].rep) //这里原来没写while,调了半个晚上
{
str1.modify(1,1,tot,a[pl].age,1);
pl--;
}
int l=find(pos,0),r=find(pos,1);
val[i]=str1.query_sum(1,1,tot,l,r);
//printf("[%d,%d],val[%d]=%d\n",l,r,i,val[i]);
}
}
void work()
{
str1.init(),str2.init();
n=read(),k=read();
for(int i=1;i<=n;i++) a[i].rep=read(),a[i].id=i;
for(int i=1;i<=n;i++) a[i].age=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) rnk[a[i].id]=i;
discrete();//离散化年龄
pre();//预处理每一个人当老板的最大人数
int qu=read();
for(int i=1;i<=qu;i++)
{
int x=read(),y=read();
if(a[rnk[x]].rep>a[rnk[y]].rep) q[i]=(ask){y,x};
else q[i]=(ask){x,y};
q[i].id=i;
}
sort(q+1,q+qu+1);
/*
printf("q:");
for(int i=1;i<=qu;i++) printf("(%d,%d) ",q[i].x,q[i].y);
printf("\n");
*/
int pl=1;
for(int i=1;i<=qu;i++)//q[]询问按照rep降序
{
while(pl<=n&&a[pl].rep>=a[rnk[q[i].y]].rep)//a[]按照rep降序
{
str2.modify(1,1,tot,a[pl].age,val[pl]);
pl++;
}
int x=max(a[rnk[q[i].y]].age,a[rnk[q[i].x]].age);
int y=min(a[rnk[q[i].y]].age,a[rnk[q[i].x]].age);
int l=find(x,0);
int r=find(y,1);
// printf("max[%d,%d]\n",l,r);
if(l>r) res[q[i].id]=-1;
else res[q[i].id]=str2.query_max(1,1,tot,l,r);
}
for(int i=1;i<=qu;i++) printf("%d\n",!res[i]?-1:res[i]);
}
int main()
{
int T=read();
while(T--) work();
return 0;
}
/*
1
10 5
10 2 7 3 10 3 9 10 6 3
7 5 9 2 3 9 1 6 5 7
10
10 3
7 10
2 4
9 6
5 1
8 9
7 10
5 7
8 7
7 6
*/