博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

CF GYM. 102861M. Machine Gun(主席树)

题目链接


简直是傻了做的时候连主席树都不会用了

容易发现,合法的点\((x,y)\)若满足询问\((qx,qy)\),则需满足\(2y-x\leq 2qy-qx,\ 2y+x\geq 2qy+qx\),将点\((x,y)\)变为\((2y-x,2y+x)\),就是一个二维偏序。
强制在线,最简单的办法就是线段树套线段树(TLE on #2),或是按\(x\)排序后对\(y\)轴建主席树。
还有一个在线方法是区间树(std,但是我的TLE on #5/whl,是我太菜了):换一下表示方式,题意等价于求与\([2qy+qx,2qy-qx]\)相交的所有区间,用线段树+区间树可以实现(纯区间树应该做不了吧,所以常数很大)。区间树见这儿,很裸。

记一下主席树的细节:纵坐标\(y_i\)\((n+1)\times y_i+i\)进行储存和离散化,这样一是没有可持久化要存\(vector\)的问题,二是主席树\(Query\)出来的答案就是按标号排好序的(不需再排序)。
为了方便可以用\((y_i<<18)+i\),这样某个\(y\)位置的编号就是\(y\&((1<<18)-1)\)。(最好用\(2y+x\)作为\(y\)\(y\)做编号时为正数?)


主席树:

//296ms	19600KB
#include <bits/stdc++.h>
#define pc putchar
#define gc() getchar()
#define pb emplace_back
#define mod 1000000007
typedef long long LL;
const int N=1e5+5,M=(1<<18)-1;

int root[N],cnt,Ans[N];
LL X[N],Y[N],pw[N];
struct Node
{
	LL x,y;
	bool operator <(const Node &a)const
	{
		return x<a.x;
	}
}A[N];
struct President_Tree
{
	#define S N*19
	#define ls son[x][0]
	#define rs son[x][1]
	#define lson ls,son[y][0],l,m
	#define rson rs,son[y][1],m+1,r
	int tot,son[S][2];
	#undef S
	void Insert(int &x,int y,int l,int r,int p)
	{
		x=++tot;
		if(l==r) return;
		int m=l+r>>1;
		p<=m?(rs=son[y][1],Insert(lson,p)):(ls=son[y][0],Insert(rson,p));
	}
	void Query(int x,int l,int r,int p)//p~N
	{
		if(!x) return;
		if(l==r) {Ans[++cnt]=Y[l]&M; return;}
		int m=l+r>>1;
		p<=m && (Query(ls,l,m,p),0);
		Query(rs,m+1,r,p);
	}
}T;

inline int read()
{
	int now=0,f=1; char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now*f;
}
int Find(int r,LL v)//the first num satisfying >=v
{
	int l=1,mid;
	while(l<r)
		if(Y[mid=l+r>>1]<v) l=mid+1;
		else r=mid;
	return l;
}
int Find2(int r,LL v)//the first num satisfying <=v
{
	if(X[1]>v) return 0;
	int l=1,mid,ans=0;
	while(l<=r)
		if(X[mid=l+r>>1]<=v) l=mid+1,ans=mid;
		else r=mid-1;
	return ans;
}

int main()
{
	int n=read(),Q=read();
	pw[0]=1;
	for(int i=1; i<=n; ++i) pw[i]=pw[i-1]*5782344%mod;
	for(int i=1; i<=n; ++i)
	{
		LL x=read(),y=read();
		A[i].x=2*y-x, Y[i]=A[i].y=((2*y+x)<<18)+i;
	}

	std::sort(A+1,A+1+n), std::sort(Y+1,Y+1+n);
	for(int i=1; i<=n; ++i) X[i]=A[i].x;
	for(int i=1; i<=n; ++i) T.Insert(root[i],root[i-1],1,n,Find(n,A[i].y));

	for(int p=0; Q--; )
	{
		LL x=-1-((p+read())%mod),y=(p+read())%mod;
		if(2*y+x>Y[n]) {printf("%d\n",p=0); continue;}

		int R1=Find2(n,2*y-x),L2=Find(n,(2*y+x)<<18);
		cnt=0, T.Query(root[R1],1,n,L2);

		LL res=0;
		std::sort(Ans+1,Ans+1+cnt);
		LL *pw_=pw;
		for(int *a=Ans+1,*lim=Ans+cnt+1; a!=lim; ++a,++pw_) res+=(*a)*(*pw_)%mod;
		p=(int)(res%mod), printf("%d\n",p);
	}

	return 0;
}

区间树:

/*
TLE on #5
*/
#include <bits/stdc++.h>
#define pc putchar
#define gc() getchar()
#define pb emplace_back
#define mod 1000000007
#define Vec std::vector<Node>
typedef long long LL;
const int N=(1e5+5)*2;//*2

#define De 0
struct Node
{
	int l,r,id;
	bool operator <(const Node &x)const
	{
		return l!=x.l?l<x.l:r<x.r;
	}
	bool operator <=(const Node &x)const
	{
		id<x.id;
	}
	bool operator !=(const Node &x)const
	{
		return id!=x.id;
	}
	void P() {printf("%d~%d %d\n",l,r,id);}
}node[N];
std::vector<int> Ans,Ans2;

//inline bool Cmp(const Node &a,const Node &b)
//{
//	return a.l!=b.l?a.l<b.l:a.r<b.r;
//}

inline void Merge(std::vector<int> &rt,std::vector<int> &a,std::vector<int> &b)
{
	std::vector<int> tmp;
	auto l=a.begin(),le=a.end(),r=b.begin(),re=b.end();
	while(l!=le&&r!=re)
		if(*l<*r) tmp.pb(*l++);
		else if(*l>*r) tmp.pb(*r++);
		else tmp.pb(*l++), r++;
	while(l!=le) tmp.pb(*l++);
	while(r!=re) tmp.pb(*r++);
	int las=0; std::vector<int>().swap(rt);//先用完a,b再清空!
	for(auto i:tmp)
		if(i!=las) rt.pb(i), las=i;
}
struct Segment_Tree
{
	#define S N<<2
	#define ls rt<<1
	#define rs rt<<1|1
	#define lson l,m,ls
	#define rson m+1,r,rs
	int son[S][2];
	std::vector<int> vec[S];
	#undef S
	void Insert(int l,int r,int rt,int p,int id)
	{
		if(l==r) {vec[rt].pb(id); return;} 
		int m=l+r>>1;
		p<=m?Insert(lson,p,id):Insert(rson,p,id);
	}
	void Maintain(int l,int r,int rt)
	{
		if(l==r) return;
		int m=l+r>>1;
		Maintain(lson), Maintain(rson), Merge(vec[rt],vec[ls],vec[rs]);
	}
	void Query(int l,int r,int rt,int L,int R)
	{
		if(L<=l && r<=R) {Merge(Ans,Ans,vec[rt]); return;}
		int m=l+r>>1;
		if(L<=m) Query(lson,L,R);
		if(m<R) Query(rson,L,R);
	}
	#undef ls
	#undef rs
	#undef lson
	#undef rson
}ST;
struct Interval_Tree
{
	#define S N*19//N<<2
	#define ls son[rt][0]
	#define rs son[rt][1]
	int tot,A[N<<1],son[S][2],center[S];
	Vec Sa[S],Sb[S];
	#undef S
	void Build(int &rt,Vec &va,Vec &vb)
	{
		int t=va.size();
		if(!t) {rt=0; return;}
		int cnt=0; !rt&&(rt=++tot);
		for(auto i:va) A[++cnt]=i.l, A[++cnt]=i.r;
		std::nth_element(A+1,A+t,A+1+cnt);//O(n)找中位数 
		int xc=A[t]; center[rt]=xc;
//		if(De)
//		{
//			printf("\nrt:%d\nA:",rt);
//			for(auto i:va) i.P();
//			printf("B:"); for(auto i:vb) i.P();
//			printf("center:%d\n",xc);
//		}
		Vec val,vbl,var,vbr;
		for(auto i:va)
			if(i.r<xc) val.pb(i);
			else if(i.l>xc) var.pb(i);
			else Sa[rt].pb(i);
		for(auto i:vb)
			if(i.r<xc) vbl.pb(i);
			else if(i.l>xc) vbr.pb(i);
			else Sb[rt].pb(i);
		Build(ls,val,vbl), Build(rs,var,vbr);
	}
	#define Update() std::sort(tmp.begin(),tmp.end()), Merge(Ans2,Ans2,tmp)
//	#define Update() rt
	void Query(int rt,int p)
	{
		if(!rt) return;
		std::vector<int> tmp;
		if(p==center[rt])
		{
			for(auto i:Sa[rt]) tmp.pb(i.id);
			Update();
		}
		else if(p<center[rt])
		{
			for(auto i:Sa[rt])
				if(i.l<=p) tmp.pb(i.id); else break;
			Update(), Query(ls,p);
		}
		else
		{
			for(auto i:Sb[rt])
				if(i.r>=p) tmp.pb(i.id); else break;
			Update(), Query(rs,p);
		}
	}
}IT;
struct Array
{
	int cnt;
	LL A[N],B[N],Ref[N];
	int Find(LL v)
	{
		if(Ref[cnt]<v) return cnt+1;
		int l=1,r=cnt,mid;
		while(l<r)
			if(Ref[mid=l+r>>1]<v) l=mid+1;
			else r=mid;
		return l;
	}
	int Find2(LL v)
	{
		if(Ref[1]>v) return 0;
		int l=1,r=cnt,mid,ans=0;
		while(l<=r)
			if(Ref[mid=l+r>>1]<=v) l=mid+1,ans=mid;
			else r=mid-1;
		return ans;
	}
	void Discrete(const int n)
	{
		const int m=n<<1;
		for(int i=1; i<=n; ++i) Ref[(i<<1)-1]=A[i], Ref[i<<1]=B[i];
		std::sort(Ref+1,Ref+1+m);
		cnt=1;
		for(int i=2; i<=m; ++i) if(Ref[i]!=Ref[i-1]) Ref[++cnt]=Ref[i];
		for(int i=1; i<=n; ++i) A[i]=Find(A[i]), B[i]=Find(B[i]);
	}
}A;

inline int read()
{
	int now=0,f=1; char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now*f;
}
bool cmpl(const Node &a,const Node &b)
{
	return a.l<b.l;
}
bool cmpr(const Node &a,const Node &b)
{
	return a.r>b.r;
}

int main()
{
	int n=read(),Q=read();
	for(int i=1; i<=n; ++i)
	{
		LL x=read(),y=read();
		A.A[i]=2*y-x, A.B[i]=2*y+x;
	}
	A.Discrete(n);
//ST
	int cnt=A.cnt;
	for(int i=1; i<=n; ++i)
	{
		node[i]=(Node){A.A[i],A.B[i],i};
		ST.Insert(1,cnt,1,A.A[i],i), ST.Insert(1,cnt,1,A.B[i],i);
	}
	ST.Maintain(1,cnt,1);
//IT
	Vec a,b; int root=0;
	for(int i=1; i<=n; ++i) a.pb(node[i]),b.pb(node[i]);
	std::sort(a.begin(),a.end(),cmpl), std::sort(b.begin(),b.end(),cmpr);
	IT.Build(root,a,b);
//Query
	for(int p=0; Q--; )
	{
		LL x=-1-((p+read())%mod),y=(p+read())%mod;
		int L=A.Find(2*y+x),R=A.Find2(2*y-x);
		std::vector<int>().swap(Ans), std::vector<int>().swap(Ans2);
//
		if(L<=R)
		{
			ST.Query(1,cnt,1,L,R), IT.Query(root,L);
//			if(De) {puts("ST Query:"); for(auto a:Ans) printf("%d ",a); De&&pc('\n');}
			std::vector<int> tmp;
			for(auto i:Ans2) if(node[i].l<=L && node[i].r>=R) tmp.pb(i);
//			if(De) {puts("IT Query:"); for(auto a:tmp) printf("%d ",a); De&&pc('\n');}
			Merge(Ans,Ans,tmp);
		}
//
		LL res=0,t=1; int las=-1;
		for(auto a:Ans)
			if(a!=las) res+=a*t%mod, t=t*5782344%mod, las=a;
		printf("%d\n",p=(int)(res%mod));//(int)(res%mod)!=(int)res%mod!
	}

	return 0;
}

线段树套线段树:

/*
TLE on #2
*/
#include <bits/stdc++.h>
#define pc putchar
#define gc() getchar()
#define mod 1000000007
typedef long long LL;
const int N=1e5+5;
//const LL M1=2e9,M2=3000000000ll,M3=1e9;

std::vector<int> Ans;
struct Segment_Tree_2D
{
	#define S N*170
	#define ls son[x][0]
	#define rs son[x][1]
	#define lson ls,l,m
	#define rson rs,m+1,r
	int tot,cntB,son[S][2],p,id,L,R;
	std::vector<int> vec[S];
	#undef S
	void Ins(int &x,int _p,int _id)
	{
		p=_p, id=_id, Insert(x,1,cntB);
	}
	void Insert(int &x,int l,int r)
	{
		if(!x) x=++tot; vec[x].emplace_back(id);
		if(l==r) return;
		int m=l+r>>1; p<=m?Insert(lson):Insert(rson);
	}
	void Qry(int x,int _L,int _R)
	{
		L=_L, R=_R, Query(x,1,cntB);
	}
	void Query(int x,int l,int r)
	{
		if(!x) return;
		if(L<=l && r<=R)
		{
			for(auto a:vec[x]) Ans.emplace_back(a);
			return;
		}
		int m=l+r>>1;
		if(L<=m) Query(lson);
		if(m<R) Query(rson);
	}
	#undef ls
	#undef rs
	#undef lson
	#undef rson
};
struct Segment_Tree_1D
{
	#define S N
	#define ls son[x][0]
	#define rs son[x][1]
	#define lson ls,l,m
	#define rson rs,m+1,r
	int tot,cntA,son[S][2],root[S],id,p1,p2,L1,R1,L2,R2;
	Segment_Tree_2D T;
	#undef S
	void Ins(int &x,int _p1,int _p2,int _id)
	{
		p1=_p1, p2=_p2, id=_id, Insert(x,1,cntA);
	}
	void Insert(int &x,int l,int r)
	{
		if(!x) x=++tot; T.Ins(root[x],p2,id);
		if(l==r) return;
		int m=l+r>>1; p1<=m?Insert(lson):Insert(rson);
	}
	void Qry(int x,int _L1,int _R1,int _L2,int _R2)
	{
		if(_L1<=_R1 && _L2<=_R2)
			L1=_L1, R1=_R1, L2=_L2, R2=_R2, Query(x,1,cntA);
	}
	void Query(int x,int l,int r)
	{
		if(!x) return;
//		printf("Query(%d %lld~%lld %lld~%lld %lld~%lld)\n",x,l,r,L1,R1,L2,R2);
		if(L1<=l && r<=R1)
		{
			T.Qry(root[x],L2,R2);
			return;
		}
		int m=l+r>>1;
		if(L1<=m) Query(lson);
		if(m<R1) Query(rson);
	}
}T;
struct Array
{
	int cnt,val[N];
	LL A[N],Ref[N];
	int Find(LL v)
	{
		if(Ref[cnt]<v) return cnt+1;
		int l=1,r=cnt,mid;
		while(l<r)
			if(Ref[mid=l+r>>1]<v) l=mid+1;
			else r=mid;
		return l;
	}
	int Find2(LL v)
	{
		if(Ref[1]>v) return 0;
		int l=1,r=cnt,mid,ans=0;
		while(l<=r)
			if(Ref[mid=l+r>>1]<=v) l=mid+1,ans=mid;
			else r=mid-1;
		return ans;
	}
	void Discrete(const int n)
	{
		for(int i=1; i<=n; ++i) Ref[i]=A[i];
		std::sort(Ref+1,Ref+1+n);
		cnt=1;
		for(int i=2; i<=n; ++i) if(Ref[i]!=Ref[i-1]) Ref[++cnt]=Ref[i];
		for(int i=1; i<=n; ++i) val[i]=Find(A[i]);
	}
}A,B;

inline int read()
{
	int now=0,f=1; char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now*f;
}
#define De 0
int main()
{
	int n=read(),Q=read();
	int root=0;
	for(int i=1; i<=n; ++i)
	{
		LL x=read(),y=read();
		A.A[i]=x+2*y, B.A[i]=2*y-x;
	}
	A.Discrete(n), B.Discrete(n);
	int cntA=A.cnt,cntB=B.cnt;
	T.cntA=A.cnt, T.T.cntB=B.cnt;
	for(int i=1; i<=n; ++i) T.Ins(root,A.val[i],B.val[i],i);
	for(int p=0; Q--; )
	{
		LL x=-1-((p+read())%mod),y=(p+read())%mod;
//		De&&printf("(%d,%d)\n",x,y);
		int L1=A.Find(2*y+x),R1=cntA,L2=1,R2=B.Find2(2*y-x);
//		De&&printf("%d~%d %d~%d  %d %d\n",L1,R1,L2,R2,2*y+x,2*y-x);
		Ans.clear(), T.Qry(root,L1,R1,L2,R2);
		LL res=0,t=1;
		std::sort(Ans.begin(),Ans.end());
		if(De) for(auto a:Ans) printf("%d ",a); De&&pc('\n');
		for(auto a:Ans) res+=a*t%mod, t=t*5782344%mod;
		p=(int)(res%mod);
		printf("%d\n",p);
	}

	return 0;
}
posted @ 2021-02-10 23:12  SovietPower  阅读(138)  评论(0编辑  收藏  举报