您的位置:首页 > 产品设计 > UI/UE

[CC-CHANOQ]Chef and odd queries

2018-03-13 14:08 405 查看

题目大意:
  给定$n(10^5)$个线段$[l_i,r_i](1\leq l_i,r_i\leq n)$,有$q(q\leq10^5)$组询问,每次给出$m_i(\sum m_i\leq n)$个点$x_{i,j}(1\leq x_{i,j}\leq n)$,问这些线段中有多少个线段覆盖了这些点中的奇数个点。

思路:
  $q$比较小时,只需要对于每个位置$i$,处理位置$1\sim i$的点数前缀和。然后即可$O(1)$判断每个线段覆盖的点数的奇偶性。单笔询问时间复杂度$O(n+m)$。
  由于$\sum m_i$有限制,所以当$q$比较大时,$m_i$就不会很大。可以用主席树记录对于$1\sim i$之间的左端点,每个区间内的右端点有多少。询问时对$x_{i,j}$排序,$O(m^2)$枚举线段覆盖了哪些点,用主席树求出符合条件的线段数即可。时间复杂度$O(m^2\log n)$。
  因此对于每次询问不同的$m_i$,令较大的$m_i$执行$O(n+m)$的算法,令较小的$m_i$执行$O(m^2\log n)$的算法即可。

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=1e5+1,M=1e5+2,logN=18;
int p[M],cnt
;
std::pair<int,int> seg
;
class FotileTree {
private:
struct Node {
int sum,left,right,vis;
};
Node node[N*logN];
int sz,new_node(const int &p,const int &id) {
node[++sz]=node

; node[sz].vis=id; return sz; } public: int root ; void modify(int &p,const int &b,const int &e,const int &x,const int &id) { if(node[p].vis!=id) p=new_node(p,id); node[p].sum++; if(b==e) return; const int mid=(b+e)>>1; if(x<=mid) modify(node[p].left,b,mid,x,id); if(x>mid) modify(node[p].right,mid+1,e,x,id); } int query(const int &p,const int &q,const int &b,const int &e,const int &l,const int &r) const { if(b==l&&e==r) return node[q].sum-node[p].sum; const int mid=(b+e)>>1; int ret=0; if(l<=mid) ret+=query(node[p].left,node[q].left,b,mid,l,std::min(mid,r)); if(r>mid) ret+=query(node[p].right,node[q].right,mid+1,e,std::max(mid+1,l),r); return ret; } void reset() { sz=0; } }; FotileTree t; int main() { for(register int T=getint();T;T--) { t.reset(); const int n=getint(); for(register int i=1;i<=n;i++) { const int l=getint(),r=getint(); seg[i]=std::make_pair(l,r); } std::sort(&seg[1],&seg +1); for(register int i=1,j=1;i<=n;i++) { t.root[i]=t.root[i-1]; for(;j<=n&&seg[j].first==i;j++) { t.modify(t.root[i],1,n,seg[j].second,i); } } for(register int i=getint();i;i--) { const int m=getint(); for(register int i=1;i<=m;i++) p[i]=getint(); int ans=0; if(m<=50) { p[m+1]=n+1; std::sort(&p[1],&p[m]+1); for(register int i=1;i<=m;i++) { if(p[i]==p[i-1]) continue; for(register int j=i;j<=m;j+=2) { if(p[j]==p[j+1]) continue; ans+=t.query(t.root[p[i-1]],t.root[p[i]],1,n,p[j],p[j+1]-1); } } } else { for(register int i=1;i<=n;i++) cnt[i]=0; for(register int i=1;i<=m;i++) cnt[p[i]]++; for(register int i=1;i<=n;i++) cnt[i]+=cnt[i-1]; for(register int i=1;i<=n;i++) { ans+=(cnt[seg[i].second]-cnt[seg[i].first-1])&1; } } printf("%d\n",ans); } } return 0; }

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: