1. 程式人生 > >CodeForces - 652D Nested Segments(線段樹/樹狀陣列+離散化)

CodeForces - 652D Nested Segments(線段樹/樹狀陣列+離散化)

題目連結

看了大佬的部落格:https://blog.csdn.net/chenquanwei_/article/details/79137969

 

題意:給n個線段的左右端點,問每個線段包括多少線段;類似於https://blog.csdn.net/weixin_42754600/article/details/81914015

把左右端點看成x,y座標,先離散化一下,然後按照x降序,x相等y升序排列一下,計算每個點前面有多少個y座標小於等於它就行了;

離散化就是把資料範圍變小,但是不改變相對大小,比如(-1e9,0,1e9) 離散化以後是(1,2,3) ; 計算起來方便

 

線段樹;

#include<cstdio>
#include<iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int maxn = 2e5+10;
int a[maxn],t[maxn<<2],y;

struct node{
    int x,y,s,t;//x,y是左右區間,s是輸入的順序,t是包含多少線段
}no[maxn];

bool cmp1(node a,node b){
    return a.x>b.x||(a.x==b.x&&a.y<b.y);
}

bool cmp2(node a,node b){
    return a.s<b.s;
}

int query(int l,int r,int rt){
    int ans = 0;
    if(r <= y) ans+=t[rt];
    else if(y < l) return 0;
    else{
        int mid = (l+r)>>1;
        ans += query(l,mid,rt<<1);
        ans += query(mid+1,r,rt<<1|1);
    }
    return ans;
}

void update(int l,int r,int rt){
    if(l == r){
        t[rt]++;
        return;
    }
    int mid = (l+r)>>1;
    if(y<=mid) update(l,mid,rt<<1);
    else update(mid+1,r,rt<<1|1);
    t[rt]++;
}

int main()
{
    int n;
    while(cin>>n){
        int k = n;
        memset(no,0,sizeof(no));
        memset(a,0,sizeof(a));
        memset(t,0,sizeof(t));
        for(int i = 0;i < k;i++){
            cin>>no[i].x>>a[i];
            no[i].y = a[i];
            no[i].s = i;
        }
        sort(a, a + n);
        n = unique(a, a + n) - a;
        for(int i = 0; i < k; i++)
           no[i].y = lower_bound(a, a + n, no[i].y) - a+1;//離散化,加一是不要零,從一開始
        sort(no,no+n,cmp1);
        for(int i = 0; i < k; i++){
            y = no[i].y;
            no[i].t = query(0,maxn,1);//查詢
            update(0,maxn,1);//更新
        }
        sort(no,no+n,cmp2);
        for(int i = 0; i < k; i++) cout<<no[i].t<<endl;
    }
    return 0;
}

 

 

樹狀陣列:

#include<cstdio>
#include<iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int maxn = 2e5+10;
int a[maxn],t[maxn],y;

struct node{
    int x,y,s,t;//x,y是左右區間,s是輸入順序,t是包含多少區間
}no[maxn];

bool cmp1(node a,node b){
    return a.x>b.x||(a.x==b.x&&a.y<b.y);
}

bool cmp2(node a,node b){
    return a.s<b.s;
}

int lowbit(int x){
    return x&(-x);
}

int query(int x){
    int ans = 0;
    while(x){
        ans += t[x];
        x -= lowbit(x);
    }
    return ans;
}

void update(int x){
    while(x<=maxn){
        t[x]++;
        x += lowbit(x);
    }
    return;
}

int main()
{
    int n;
    while(cin>>n){
        int k = n;
        memset(no,0,sizeof(no));
        memset(a,0,sizeof(a));
        memset(t,0,sizeof(t));
        for(int i = 0;i < k;i++){
            cin>>no[i].x>>a[i];
            no[i].y = a[i];
            no[i].s = i;
        }
        sort(a, a + n);
        n = unique(a, a + n) - a;
        for(int i = 0; i < k; i++)
           no[i].y = lower_bound(a, a + n, no[i].y) - a+1;//離散化,加一是不要零,從一開始
        sort(no,no+n,cmp1);
        for(int i = 0; i < k; i++){
            y = no[i].y;
            no[i].t = query(y);//查詢
            update(y);//更新
        }
        sort(no,no+n,cmp2);
        for(int i = 0; i < k; i++) cout<<no[i].t<<endl;
    }
    return 0;
}