luogu P7470 [NOI Online 2021 提高组] 岛屿探险(民间数据)

题面传送门
考试时写树套树结果没写完一分没有。靠暴力水了\(20\)分。
首先肯定要\(b,d\)分开讨论。
如果\(b>d\)显然先将所有\(a\)插入字典树然后把\((c,d)\)这一组拿去查即可。
考虑\(b<d\)怎么做。发现如果将\(c\)插入,\((a,b)\)当做询问插入其实是一样的,所以先将每个二元组插进去然后查询即可。
然后上cdq分治就好了。
code:

#include<cstdio>
#include<algorithm>
#define I inline
#define re register
#define N 100039
using namespace std;
int n,m,k,x,y,z,head,a,b,ans[N],root;
struct yyy{int x,c,d,id,flag;}f[N*3],g[N*3];
I bool cmp1(yyy x,yyy y){return x.x==y.x?(x.id<y.id):(x.x<y.x);}
I void merge(int x,int y){
	re int m=x+y>>1,i,head=x-1,l=x,r=m+1;
	while(l<=m||r<=y)(r==y+1||(l<=m&&f[l].d<=f[r].d))?(g[++head]=f[l++]):(g[++head]=f[r++]);
	for(i=x;i<=y;i++) f[i]=g[i];
}
struct Trie{
	int ch[2][N*50],f[N*50],cnt;
	I void make(int &now){(!now)&&(now=++cnt);}
	I void clear(){for(int i=0;i<=cnt;i++)ch[0][i]=ch[1][i]=f[i]=0;cnt=0;}
	I void get(int x,int &now,int d=25){(!now)&&(now=++cnt);f[now]++;if(d==-1) return;get(x,ch[(x>>d)&1][now],d-1);}
	I int find(int c,int d,int now,int de=25){
		if(de==-1||!now) return f[now];int nc=(c>>de)&1;
		return ((d>>de)&1)?(f[ch[nc][now]]+find(c,d,ch[!nc][now],de-1)):(find(c,d,ch[nc][now],de-1));
	}
	I void gets(int c,int d,int &now,int de=25){
		(!now)&&(now=++cnt);if(de==-1) return(void)(f[now]++);int nc=(c>>de)&1;
		((d>>de)&1)?(make(ch[nc][now]),f[ch[nc][now]]++,gets(c,d,ch[!nc][now],de-1)):(gets(c,d,ch[nc][now],de-1));return;
	}
	I int finds(int x,int now,int d=25){if(d==-1||!now) return f[now];return f[now]+finds(x,ch[(x>>d)&1][now],d-1);}
}s;
I void solve(int l,int r){
	if(l==r) return;int m=l+r>>1,i,ri;
	solve(l,m);solve(m+1,r);root=0;s.clear();ri=m;
	for(i=r;i>m;i--) {
		while(ri>=l&&f[ri].d>=f[i].d) (!f[ri].flag)&&(s.get(f[ri].c,root),0),ri--;
		f[i].flag&&(ans[f[i].id]+=s.find(f[i].c,f[i].d,root)*f[i].flag);
	}root=0,s.clear(),ri=l;
	for(i=m+1;i<=r;i++){
		while(ri<=m&&f[ri].d<f[i].d) (!f[ri].flag)&&(s.gets(f[ri].c,f[ri].d,root),0),ri++;
		f[i].flag&&(ans[f[i].id]+=s.finds(f[i].c,root)*f[i].flag);
	}
	merge(l,r);
} 
int main(){
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	register int i;
	scanf("%d%d",&n,&m);head=n;
	for(i=1;i<=n;i++) scanf("%d%d",&f[i].c,&f[i].d),f[i].x=i;
	for(i=1;i<=m;i++)scanf("%d%d%d%d",&x,&y,&a,&b),(x^1)&&(f[++head]=(yyy){x-1,a,b,i,-1},0),f[++head]=(yyy){y,a,b,i,1};
	sort(f+1,f+head+1,cmp1);solve(1,head);for(i=1;i<=m;i++) printf("%d\n",ans[i]);
}
上一篇:通过nc命令在应用层实现网络连接


下一篇:Linux下TCP,UDP端口连接确认