洛谷P3801 紅色的幻想鄉

洛谷P3801 紅色的幻想鄉

1<=n,m<=100000……二維線段樹廢了。

然而再看看這個題,起始點沒有紅霧,就像:
1ge

兩個重複的會抵消,便是這樣:
這裏寫圖片描述

那麼,站的位置可否當做抵消掉的呢?
上邊圖中的紅霧數量,可以是:

×+×

行、列的長度就是題中m,n,抵消塊數呢?

在算行列時,每一個交叉點是記了兩次的。圖中有多少交叉點呢?記放過的行數x,放過的列數y,每行每列交叉1個,抵消塊數就是2xy。

到現在,求出x,y就擁有了一切!

行列有多少?區間求和。每次放紅霧?單點修改。標準線段樹。
當站在放過的那行(列)上時,整一行就消了。在上圖中,假設在 ( 4 , 3 )點放一次,變成:
這裏寫圖片描述
站的那點本來就紅,放一下不影響。而原來白的變紅了,不就是沒放那一行嗎!
若是站在以前站過的點上,同樣的道理。

修改時直接異或,0改11改0完事。

#include<iostream>
#include<cstdio>
#define now int l,int r,int num
#define ls l,l+r>>1,num<<1
#define rs (l+r>>1)+1,r,num<<1|1
using namespace std;
int y[262150],x[262150];
int x1,y1,x2,y2;
int n,m,q;
void update(int *a,int num){
    a[num]=a[num<<1]+a[num<<1|1];
    }
void change(int *a,int p,now){
    if(l==r){
        a[num]^=1;
        return;
        }
    int mid=l+r>>1;
    if(p<=mid)change(a,p,ls);
    else change(a,p,rs);
    update(a,num);
    }

int que(int *a,int al,int ar,now){
    if(al<=l&&r<=ar)
        return a[num];
    int mid=l+r>>1,ans=0;
    if(al<=mid)ans+=que(a,al,ar,ls);
    if(mid<ar)ans+=que(a,al,ar,rs);
    return ans;
    }
int main(){
    scanf("%d%d%d",&n,&m,&q);
    while(q--){
        int cmd;
        scanf("%d",&cmd);
        if(cmd==1){
            int x0,y0;
            scanf("%d%d",&x0,&y0);
            change(x,x0,1,n,1);
            change(y,y0,1,m,1);
            }
        else{
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            long long xx=que(x,x1,x2,1,n,1),
                      yy=que(y,y1,y2,1,m,1);
            printf("%lld\n",xx*(long long)(y2-y1+1)+
                    yy*(long long)(x2-x1+1)-
                    (long long)(xx*yy<<1));
            }
        }
    return 0;
    }

懶得複製一遍再改了,直接傳數組指針。
記得開long long!十萬×十萬爆int了!

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