2015多校第7场 HDU 5372 Segment Game 树状数组,思维

来源:互联网 发布:程序员需要考什么证书 编辑:程序博客网 时间:2024/06/07 12:05

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5372

题意:给你n次操作,每次增加线段或者删除第i次增加操作中增加的线段,问你每次增加操作中,所增加的线段会覆盖多少条完整的线段。

解法:对于新插入的线段,查询有多少个线段左端点大于等于该线段的左端点。 再查询有多少个线段的右端点大于该线段右端点, 两者之差就是答案。用两个树状数组搞定。时间复杂度nlogn


#include <bits/stdc++.h>using namespace std;const int maxn=4e5+10;int a[maxn],b[maxn],op[maxn],c[2][maxn];vector<int>v;int getid(int x){    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}inline lowbit(int x){    return x&-x;}void add(int x, int v, int o){    while(x<maxn){        c[o][x]+=v;        x+=lowbit(x);    }}int query(int x, int o){    int ret=0;    while(x){        ret += c[o][x];        x-=lowbit(x);    }    return ret;}int main(){    int n,ks=0;    while(~scanf("%d", &n))    {        int clk=0;        for(int i=1; i<=n; i++){            scanf("%d %d", &op[i], &a[i]);            if(op[i]==0){                b[i]=a[i]+(++clk);                v.push_back(a[i]);                v.push_back(b[i]);            }        }        sort(v.begin(),v.end());        v.erase(unique(v.begin(),v.end()),v.end());        memset(c,0,sizeof(c));        clk = 1;        printf("Case #%d:\n", ++ks);        for(int i=1; i<=n; i++){            if(op[i]==0){                int l=getid(a[i]),r=getid(b[i]);                printf("%d\n", query(r,1)-query(l-1,0));                a[clk]=l;                b[clk++]=r;                add(l,1,0);                add(r,1,1);            }            else{                add(a[a[i]], -1, 0);                add(b[a[i]], -1, 1);            }        }    }    return 0;}


阅读全文
0 0