CodeForces - 369E Valera and Queries(树状数组)

[CodeForces - 369E Valera and Queries](http://codeforces.com/problemset/problem/369/E) 题目大意:给出n个线段(线段的左端点和右端点坐标)和m个查询,每个查询有cnt个点,要求给出有多少条线段包含至少其中一个点。 思路:如果按照题意正面去算有每个线段是否包含点,那么时间复杂度是不允许的;如果去算每个点被哪些线段包含,那么去重比较困难。正难则反,因此对于每个查询,选择去求有多少个线段没有覆盖任何一个点,那么答案则为n减所求。用树状数组来统计没有覆盖任何一个点的线段数,大致做法是将临界线段(如x1+1,x2-1)插入seg数组中,再按一定规则进行排序,之后通过树状数组维护统计被包含于临界线段的线段数,具体实现在代码中。 代码: ```C++ #include #include #include using namespace std; const int maxn=1000000+5; struct segment { int l,r,id; }; bool cmp(const segment& a,const segment& b) { if (a.l!=b.l) return a.l>b.l; if (a.r!=b.r) return a.r0) { sum+=tree[i]; i-=i&-i; } return sum; } int ans[maxn];

int main()
{
int n,m,i,j;
cin>>n>>m;
for (i=0;i<n;++i)
{
scanf("%d%d",&seg[i].l,&seg[i].r);
seg[i].id=0;
}
int cnt,x,pre,tt=n;
for (i=1;i<=m;++i)
{
ans[i]=n;
pre=0;
scanf("%d",&cnt);
for (j=0;j<cnt;++j)
{
scanf("%d",&x);
if (pre+1<=x-1)
{
seg[tt].l=pre+1;
seg[tt].r=x-1;
seg[tt++].id=i;
}
pre=x;
}
seg[tt].l=pre+1;
seg[tt].r=maxn;
seg[tt++].id=i;
}
sort(seg,seg+tt,cmp);
for (i=0;i<tt;++i)
{
if (seg[i].id)
{
ans[seg[i].id]-=sum(seg[i].r);
}
else
{
add(seg[i].r,1);
}
}
for (i=1;i<=m;++i)
{
printf("%d\n",ans[i]);
}
return 0;
}

</font>
posted @ 2018-05-08 21:28  __orange  阅读(192)  评论(0编辑  收藏  举报