1. 程式人生 > >【p3870】洛谷P3870開關題解

【p3870】洛谷P3870開關題解

long 自然 mes code 普通 flag 範圍 turn -m

我們先看題面,一看是一個區間操作,再看一下數據範圍,就可以很輕松地想到是用一個數據結構來加快區間查詢和修改的速度,所以我們很自然的就想到了線段樹。

但是這個題還跟普通的線段樹不一樣,這個題可以說要思考一下,我們可以知道一個區間內如果要修改的話那假如說原來有x個燈開著,那一次操作之後就變成了這個區間的長度減去x個燈。因此我們可以把懶標記確認為是否要下放因為這是棵線段樹,每一個節點都表示一個區間,那一次修改可能會修改多次這個區間所以如果這次區間修改了,那就不用修改了。

其他就跟平常的線段樹一樣了。

代碼:

#include<iostream>
#include<cstdio>
#include
<bits/stdc++.h> #define ll long long #define ls left,mid,root<<1 #define rs mid+1,right,root<<1|1 using namespace std; int ans[1000010],n,m,lazy[1000100]; void pushup(ll root) { ans[root]=ans[root<<1]+ans[root<<1|1]; } void pushdown(ll root,ll mid,ll left,ll right) {
if(lazy[root]) { lazy[root<<1]^=1; lazy[root<<1|1]^=1; ans[root<<1]=(mid-left+1)-ans[root<<1]; ans[root<<1|1]=(right-mid)-ans[root<<1|1]; lazy[root]=0; } } ll query(ll l,ll r,ll left,ll right,ll root)//區間查詢,l,r是要查詢的區間,left,right,是當前區間
{ ll res1=0,res2=0; if(l<=left&&r>=right) { return ans[root]; } ll mid=(left+right)>>1; pushdown(root,mid,left,right); if(l<=mid) res1=query(l,r,ls); if(r>=mid+1) res2=query(l,r,rs); return res1+res2; } void update(ll l,ll r,ll left,ll right,ll root) { if(l<=left&&r>=right) { lazy[root]^=1; ans[root]=(right-left+1)-ans[root]; return; } ll mid=(left+right)>>1; pushdown(root,mid,left,right); if(l<=mid) update(l,r,ls); if(r>=mid+1) update(l,r,rs); pushup(root); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int flag; int x,y; scanf("%d",&flag); scanf("%d%d",&x,&y); if(flag) printf("%d\n",query(x,y,1,n,1)); else update(x,y,1,n,1); } }

【p3870】洛谷P3870開關題解