求線段交點個數-線段樹-歐拉定理-2019暑假杭電多校1002-Rikka with Cake

題目傳送門
題解:
在這裏插入圖片描述
線段樹+離散化+歐拉定理
線段樹記得使用lazy標記,否則會TLE。

#include<bits/stdc++.h>
#define per(i,a,b) for(int i = (a);i <= (b);++i)
#define rep(i,a,b) for(int i = (a);i >= (b);--i)
#define INF 1e18
using namespace std;
#define INF 1e18
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
inline int gi(){//這個快速讀的模板比上面快,估計是沒有調用某些函數
    char a=getchar();int b=0;
    while(a<'0'||a>'9')a=getchar();
    while(a>='0'&&a<='9')b=b*10+a-'0',a=getchar();
    return b;
}
int n = 0,m = 0,k = 0;
struct node{
    int x,y;
    char dir;
}a[maxn];
int nx = 0,ny = 0;
int xx[maxn],yy[maxn];
struct Tree{
    int l,r;
    LL val;
    LL add_mark;
}tree[maxn<<2];
bool cmpx(node p1,node p2){
    return p1.x == p2.x ? p1.y < p2.y : p1.x < p2.x;
}

void push_up(int rt){
    tree[rt].val = tree[rt<<1].val + tree[rt<<1|1].val;
}
void push_down(int rt){//lazy懶惰標記,向下傳遞
    if(tree[rt].add_mark != 0){
        int len = tree[rt].r - tree[rt].l + 1;

        tree[rt<<1].add_mark += tree[rt].add_mark;
        tree[rt<<1|1].add_mark += tree[rt].add_mark;

        tree[rt<<1].val += 1ll*tree[rt].add_mark * (len-(len>>1));
        tree[rt<<1|1].val += 1ll*tree[rt].add_mark * (len>>1);

        tree[rt].add_mark = 0; 
    }
}
void build(int rt,int l,int r){
    tree[rt].l = l; tree[rt].r = r; tree[rt].val = 0;
    tree[rt].add_mark = 0;
    if(l == r){
        return ;
    }
    int mid = (l + r) >> 1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
}
void update(int rt,int L,int R,int add_val){

    if(L <= tree[rt].l && tree[rt].r <= R){//區間被包含,直接更新,並且使用lazy標記
        tree[rt].val += 1ll*add_val * (tree[rt].r - tree[rt].l + 1);
        tree[rt].add_mark += add_val;
        return ;
    }
    push_down(rt);//lazy懶惰標記,向下傳遞
    // if(tree[rt].l > R || tree[rt].r < L){//不相交
    //     return ;
    // }//其實這種情況不存在,因爲最開始是整個區間,必定包含,後面不包含的區間根本就不會遞歸到
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    if(L <= mid){
        update(rt<<1,L,R,add_val);
    }
    if(R > mid){
        update(rt<<1|1,L,R,add_val);
    }
    push_up(rt);//向上更新                                         
    return ;
}
LL query(int rt,int pos){
    if(tree[rt].l == tree[rt].r){
        return tree[rt].val; 
    }
    push_down(rt);//lazy懶惰標記,向下傳遞

    int mid = (tree[rt].l + tree[rt].r) >> 1;
    if(pos <= mid){
        return query(rt<<1,pos);
    }else{  
        return query(rt<<1|1,pos);
    }
}
LL query2(int rt,int ql,int qr){//區間查詢
    if(ql <= tree[rt].l && tree[rt].r <= qr){//區間查詢
        //要離散化區間對應好,才能得到正確答案
        return tree[rt].val;
    }
    push_down(rt);
    int mid = (tree[rt].l + tree[rt].r) >> 1;
    LL ans = 0;
    if(ql <= mid){
        ans += query2(rt<<1,ql,qr);
    }
    if(qr > mid){
        ans += query2(rt<<1|1,ql,qr);
    }
    return ans;
}

void solve(){
   
    sort(a+1,a+1+k,cmpx);//按照x從小到大的順序排序,就可以屏蔽掉後面的信息
    LL ans = 0;
    build(1,1,ny);
    per(i,1,k){//跑左邊的
        if(a[i].dir == 'U'){
            update(1,a[i].y,ny,1ll);
        }
        if(a[i].dir == 'D'){
            update(1,1,a[i].y,1ll);
        }
        if(a[i].dir == 'L'){
            ans += query(1,a[i].y);
            // ans += query2(1,a[i].y,a[i].y);
        }
    }
    build(1,1,ny);
    rep(i,k,1){//跑右邊
        if(a[i].dir == 'U'){
            update(1,a[i].y,ny,1);
        }
        if(a[i].dir == 'D'){
            update(1,1,a[i].y,1);
        }
        if(a[i].dir == 'R'){
            ans += query(1,a[i].y);
            // ans += query2(1,a[i].y,a[i].y);
        }
    }
    printf("%lld\n",ans + 1);
}
int main(){

    int T = 0;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d %d",&n,&m,&k);
        // n = gi(); m = gi(); k = gi();
        per(i,1,k){
            scanf("%d %d %c",&a[i].x,&a[i].y,&a[i].dir);
            // a[i].x = gi(); a[i].y = gi(); scanf("%c",&a[i].dir);
            xx[i] = a[i].x; yy[i] = a[i].y; 
        }   
        sort(xx+1,xx+1+k);//離散化
        nx = unique(xx+1,xx+1+k) - xx - 1;
        sort(yy+1,yy+1+k);
        ny = unique(yy+1,yy+1+k) - yy - 1;//因爲是從1開始的所以這裏要-1,才能和區間查詢一致
        per(i,1,k){
            a[i].x = lower_bound(xx+1,xx+1+nx,a[i].x) - xx;
            a[i].y = lower_bound(yy+1,yy+1+ny,a[i].y) - yy;
        }                                                          
        solve();
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章