传送门:https://ac.nowcoder.com/acm/contest/887/E
考场上早点开这题就好了,到最后也没有过样例
主要还是离散化区间变成点的这种线段树题写的太少了,上次写可能是17年暑假卢总挂的题。。。
18年湖南省赛那道题也是离散化后要用一个点代表一个区间,然而当时就不敢写那题
赛后想清楚很快就改好了,但是因为进入线段树找恰好是中位数的地方出了一些问题,WA了一发。
首先把所有要加的区间的端点进行离散化,离散化后,每个端点中间加一个点表示中间间隔的区间,numval[i]表示每个节点所代表的区间的长度,如果是端点,那么为1,如果是端点之间的区间,那么就是num[i+1]-num[i]-1,(有可能为空)
因为空间为128M,且4e5个l,r,8e5个值,16e6个离散化节点,64e6个线段树节点,所以线段树不能记录节点的区间,只能记录sum和一个tag表示这个点所表示的区间完全被加+1了多少次。
用pre[i]表示前i个点的长度共有多少,那么在线段树add函数中,就可以直接计算出每个点的sum增加了多少。
我们通过计算得到当前一共有sum个数字,那么大小为res=(sum+1)/2大的数字就是中位数,那么进入线段树去二分,如果左儿子的sum严格小于当前的res,那么res-=tree[k<<1].sum,进入右儿子。这样可以保证最后找到的叶子节点一定是res<=tree[l].sum且res是严格大于0的(这里一开始没有这样判断所以WA了一发,以后注意),那么我们只要看这个叶子节点是区间还是端点,如果是区间,那么这个tree[l].tag直接就是这个区间一共被+1了多少次,那么这个区间中的每个数字的个数都是tree[l].tag,那么就可以计算出第res个数字是哪个了。
#include<bits/stdc++.h>
#define maxl 400010
using namespace std;
int n,cnt,tot,id,kk,nxtnum,ans;
int a1,a2,b1,b2,c1,c2,mod1,mod2;
int ax[maxl],ay[maxl],ll[maxl],rr[maxl];
int num[maxl*4],numval[maxl*4];
struct node
{
long long sum;
int tag;
}tree[maxl*4*4];
long long res;
long long pre[maxl*4];
inline void prework()
{
scanf("%d",&n);
scanf("%d%d",&ax[1],&ax[2]);
scanf("%d%d%d%d",&a1,&b1,&c1,&mod1);
scanf("%d%d",&ay[1],&ay[2]);
scanf("%d%d%d%d",&a2,&b2,&c2,&mod2);
ll[1]=min(ax[1],ay[1])+1;
rr[1]=max(ax[1],ay[1])+1;
ll[2]=min(ax[2],ay[2])+1;
rr[2]=max(ax[2],ay[2])+1;
for(int i=3;i<=n;i++)
{
ax[i]=(1ll*ax[i-1]*a1+1ll*ax[i-2]*b1+c1)%mod1;
ay[i]=(1ll*ay[i-1]*a2+1ll*ay[i-2]*b2+c2)%mod2;
ll[i]=min(ax[i],ay[i])+1;
rr[i]=max(ax[i],ay[i])+1;
}
cnt=0;
for(int i=1;i<=n;i++)
num[++cnt]=ll[i],num[++cnt]=rr[i];
sort(num+1,num+1+cnt);
tot=unique(num+1,num+1+cnt)-num-1;
num[tot+1]=num[tot];
for(int i=1;i<=tot;i++)
{
numval[(i-1)*2+1]=1,numval[i*2]=num[i+1]-num[i]-1;
pre[(i-1)*2+1]=pre[(i-1)*2]+1;
pre[i*2]=pre[i*2-1]+numval[i*2];
}
for(int i=1;i<=n;i++)
{
id=lower_bound(num+1,num+1+tot,ll[i])-num;
ll[i]=(id-1)*2+1;
id=lower_bound(num+1,num+1+tot,rr[i])-num;
rr[i]=(id-1)*2+1;
}
}
inline void build(int k,int l,int r)
{
int mid=(l+r)>>1;
tree[k].tag=0;
if(l==r)
{
tree[k].sum=tree[k].tag=0;
return;
}
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
inline void gank(int k,int l,int r)
{
int mid=(l+r)>>1;
int d=tree[k].tag;
if(d>0)
{
tree[k<<1].sum+=(pre[mid]-pre[l-1])*d;
tree[k<<1].tag+=d;
tree[k<<1|1].sum+=(pre[r]-pre[mid])*d;
tree[k<<1|1].tag+=d;
tree[k].tag=0;
}
}
inline void add(int k,int l,int r,int l1,int r1)
{
if(l1!=r1)
gank(k,l1,r1);
tree[k].sum+=(pre[r]-pre[l-1]);
if(l==l1 && r==r1)
{
tree[k].tag+=1;
return;
}
int mid=(l1+r1)>>1;
if(r<=mid)
add(k<<1,l,r,l1,mid);
else if(l>mid)
add(k<<1|1,l,r,mid+1,r1);
else
{
add(k<<1,l,mid,l1,mid);
add(k<<1|1,mid+1,r,mid+1,r1);
}
}
inline int query(int k,int l,int r)
{
if(l!=r)
gank(k,l,r);
if(l==r)
{
nxtnum=tree[k].tag;
return l;
}
int mid=(l+r)>>1;
if(tree[k<<1].sum<res)
{
res-=tree[k<<1].sum;
query(k<<1|1,mid+1,r);
}
else
query(k<<1,l,mid);
}
inline void mainwork()
{
long long sum=0,tmp,k,z,y;
build(1,1,tot*2);
for(int i=1;i<=n;i++)
{
sum+=num[(rr[i]+1)/2]-num[(ll[i]+1)/2]+1;
add(1,ll[i],rr[i],1,tot*2);
res=(sum+1)/2;
id=query(1,1,tot*2);
if(id&1)
ans=num[id/2+1]-1;
else
ans=num[id/2];
ans+=res/nxtnum;
if(res%nxtnum!=0)
ans++;
printf("%d\n",ans);
}
}
int main()
{
int t;
prework();
mainwork();
return 0;
}