NOIP提高组 被粉碎的线段树

Description

NOIP提高组 被粉碎的线段树_第1张图片

Data Constraint

NOIP提高组 被粉碎的线段树_第2张图片

Solution

我们发现区间定位个数(答案)和完全被该区间包含的节点个数所相关。

具体性质如下:区间定位个数(答案) = 2 * 区间长度 - 完全被该区间包含的节点个数。对于一个区间定位,它对答案的贡献为1,设它为区间[l..r],那么完全被该区间包含的节点个数为2* (r-l+1)-1。而该区间长度的两倍为2*(r-l+1),不难发现两者一减即为对答案的贡献1。于是我们可以将多个区将定位合并起来计算答案。

因此,我们将区间和询问分别按左指针从大到小进行排序,给区间一个指针j,对于每次询问,我们将区间的左指针大于询问中左指针的区间的右指针放进一个树状数组中。那么答案即为2 * 区间长度-树状数组中右指针比当前询问小的数量。总时间复杂度为O(N logN )。

代码

#include
#include
#include
#include
#include
using namespace std;
const int maxn=200006,maxn1=20;
struct code{
    int a,b,c;
}b[maxn],c[maxn];
int n,i,t,j,k,m,num,l;
int a[maxn],x,y,f[maxn],x1,ans[maxn];
void dg(int l,int r){
    b[++num].a=l,b[num].b=r;
    if (l==r) return;
    int t=++j;
    dg(l,a[t]);
    dg(a[t]+1,r);
}
bool cmp(code x,code y){
    return x.aint lowbit(int x){
    return x & (-x);
}
void insert(int x){
    if (x>n) return;
    f[x]++;
    insert(x+lowbit(x));
}
int find(int x){
    if (!x) return 0;
    return f[x]+find(x-lowbit(x));
}
int main(){
//  freopen("data.in","r",stdin);
    scanf("%d%d",&n,&m);
    for (i=1;iscanf("%d",&a[i]);j=0;
    dg(1,n);
    sort(b+1,b+num+1,cmp);
    for (i=1;i<=m;i++)
        scanf("%d%d",&c[i].a,&c[i].b),c[i].c=i;
    sort(c+1,c+m+1,cmp);j=num;
    for (i=m;i>=1;i--){
        while (b[j].a>=c[i].a && j) insert(b[j].b),j--;
        ans[c[i].c]=2*(1+c[i].b-c[i].a)-find(c[i].b);
    }
    for (i=1;i<=m;i++)
        printf("%d\n",ans[i]);
}

你可能感兴趣的:(noip,树状数组)