zoukankan      html  css  js  c++  java
  • P7470-[NOI Online 2021 提高组]岛屿探险【Trie,CDQ分治】

    正题

    题目链接:https://www.luogu.com.cn/problem/P7470


    题目大意

    给出(n)个二元组((a,b))

    (q)次询问给出((l,r,c,d))表示询问([l,r])中有多少二元组满足(c xor aleq min(b,d))

    (1leq n,qleq 10^5)


    解题思路

    这个(min)一看就很迷,显然是让我们分两种情况讨论。

    再把询问拆一下,就变成了两个条件(posleq r/pos<l)(bleq d/b>d)

    两个偏序条件的话直接上(CDQ),然后考虑两种情况怎么处理。

    • (c xor aleq b):这样对于每个二元组合法的(c)开业被拆成(Trie)上最多(log)个区间,建(Trie)即可
    • (c xor aleq d):对于每组询问在(Trie)上跑区间求和即可。

    时间复杂度(O(nlog^2 n))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N=1e5+10,M=N*24;
    struct node{
    	int w,l,id;
    }q[N<<1],a[N];
    int n,m,tot,rt1,rt2,ans[N];
    vector<node> v[N];
    struct Trie1{
    	int cnt,ch[M][2],w[M]; 
    	void Clear(){rt1=0;cnt=0;return;}
    	int Newp(){++cnt;ch[cnt][0]=ch[cnt][1]=w[cnt]=0;return cnt;}
    	void Insert(int &x,int d,int l,int val){
    		if(!x)x=Newp();
    		if(d<0){w[x]++;return;}
    		int c=(val>>d)&1;
    		if((l>>d)&1){
    			Insert(ch[x][c^1],d-1,l,val);
    			if(!ch[x][c])ch[x][c]=Newp();
    			w[ch[x][c]]++; 
    		}
    		else Insert(ch[x][c],d-1,l,val);
    	}
    	int Ask(int x,int d,int val){
    		if(!x)return 0;
    		if(d<0)
    		return w[x];
    		int c=(val>>d)&1;
    		return Ask(ch[x][c],d-1,val)+w[x];
    	} 
    }T1;
    struct Trie2{
    	int cnt,ch[M][2],w[M];
    	void Clear(){rt2=0;cnt=0;return;}
    	int Newp(){++cnt;ch[cnt][0]=ch[cnt][1]=w[cnt]=0;return cnt;}
    	void Insert(int &x,int d,int val){
    		if(!x)x=Newp();
    		if(d<0){w[x]++;return;}
    		int c=(val>>d)&1;
    		Insert(ch[x][c],d-1,val);
    		w[x]=w[ch[x][0]]+w[ch[x][1]];
    		return;
    	}
    	int Ask(int x,int d,int l,int val){
    		if(d<0)return w[x];
    		int c=(val>>d)&1;
    		if((l>>d)&1)
    			return Ask(ch[x][c^1],d-1,l,val)+w[ch[x][c]];
    		return Ask(ch[x][c],d-1,l,val);
    	}
    }T2;
    bool cmp(node x,node y)
    {return x.l<y.l;}
    void CDQ(int l,int r){
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	CDQ(l,mid);
    	CDQ(mid+1,r);
    	sort(a+l,a+mid+1,cmp);
    	T1.Clear();T2.Clear();tot=0;
    	for(int i=mid+1;i<=r;i++)
    		for(int j=0;j<v[i].size();j++)
    			q[++tot]=v[i][j];
    	sort(q+1,q+1+tot,cmp);
    	for(int i=1,z=l;i<=tot;i++){
    		while(z<=mid&&a[z].l<=q[i].l)
    			T1.Insert(rt1,23,a[z].l,a[z].w),z++;
    		if(q[i].id<0)ans[-q[i].id]-=T1.Ask(rt1,23,q[i].w);
    		else ans[q[i].id]+=T1.Ask(rt1,23,q[i].w);
    	}
    	for(int i=tot,z=mid;i>=1;i--){
    		while(z>=l&&a[z].l>q[i].l)
    			T2.Insert(rt2,23,a[z].w),z--;
    		if(q[i].id<0)ans[-q[i].id]-=T2.Ask(rt2,23,q[i].l,q[i].w);
    		else ans[q[i].id]+=T2.Ask(rt2,23,q[i].l,q[i].w);
    	}
    	return;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		scanf("%d%d",&a[i].w,&a[i].l);
    	for(int i=1;i<=m;i++){
    		int l,r,c,d;
    		scanf("%d%d%d%d",&l,&r,&c,&d);
    		v[l].push_back((node){c,d,-i});
    		v[r+1].push_back((node){c,d,i});
    	}
    	sort(q+1,q+1+n,cmp);
    	CDQ(1,n+1);
    	for(int i=1;i<=m;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    再也不用为word 中表达式的上标和下标发愁了
    创建链接
    ps钢笔工具隐藏的知识。
    学Ps个人遇到的小细节
    新手琢磨ps,学问深着呢。。
    数据库2012终于知道数据库攻击注入参数
    想脱离鼠标,不想要鼠标就只想用键盘完成所有编程,你说可能吗?
    vs2013中的快捷键
    如何在C/C++中动态分配二维数组【转载】
    转载:C++的那些事:表达式与语句
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15214139.html
Copyright © 2011-2022 走看看