【CQOI 2006】簡單題
阿新 • • 發佈:2019-02-20
【題目】
題目背景:
CQOI 2006 T1
題目描述:
有一個 n 個元素的陣列,每個元素初始均為 0 。有 m 條指令,要麼讓其中一段連續序列數字反轉——0 變 1,1 變 0(操作1),要麼詢問某個元素的值(操作2)。例如當 n=20 時,10 條指令如下:
輸入格式:
輸入檔案第一行包含兩個整數 n,m,表示陣列的長度和指令的條數,以下 m 行,每行的第一個數 t 表示操作的種類。若 t=1,則接下來有兩個數 L, R (L ≤ R),表示區間 [L, R] 的每個數均反轉;若 t=2,則接下來只有一個數 I,表示詢問的下標。
輸出格式:
每個操作 2 輸出一行(非0即1),表示每次操作 2 的回答。
樣例資料:
輸入
20 10 1 1 10 2 6 2 12 1 5 12 2 6 2 15 1 6 16 1 11 17 2 12 2 6
輸出
1 0 0 0 1 1
備註:
【資料範圍】
50% 的資料滿足:1 ≤ n ≤ 1,000,1 ≤ m ≤ 10,000
100% 的資料滿足:1 ≤ n ≤ 100,000,1 ≤ m ≤ 500,000
【分析】
首先我們要知道,對於一個元素,如果將它反轉奇數次,那它就是 1,否則是 0
這樣的話我們就記錄一下每個元素的反轉次數,對區間 [ l , r ] 反轉就將區間 [ l , r ] 每個元素的反轉次數加一
詢問的時候,統計一下這個元素的反轉次數就行了
然後它就變成一道簡單的區間加問題,用線段樹就可以輕鬆解決
【程式碼】
可能是我們學校OJ的問題吧,cout 要比 printf 快些,不過這不是重點
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 100005 using namespace std; int tree[4*N]; void pushdown(int root) { tree[root<<1]+=tree[root]; tree[root<<1|1]+=tree[root]; tree[root]=0; } void modify(int root,int l,int r,int x,int y) { if(l>=x&&r<=y) { tree[root]++; return; } int mid=(l+r)>>1; if(tree[root]) pushdown(root); if(x<=mid) modify(root<<1,l,mid,x,y); if(y>mid) modify(root<<1|1,mid+1,r,x,y); } int find(int root,int l,int r,int x) { if(l==r) return tree[root]; int ans,mid=(l+r)>>1; if(tree[root]) pushdown(root); if(x<=mid) ans=find(root<<1,l,mid,x); else ans=find(root<<1|1,mid+1,r,x); return ans; } int main() { int n,m,i,s,x,y,ans; scanf("%d%d",&n,&m); for(i=1;i<=m;++i) { scanf("%d",&s); if(s==1) { scanf("%d%d",&x,&y); modify(1,1,n,x,y); } else { scanf("%d",&x); ans=find(1,1,n,x); if(ans&1) cout<<'1'<<'\n'; else cout<<'0'<<'\n'; } } return 0; }