Codeforce 915E(線段樹動態開點)
阿新 • • 發佈:2018-12-24
題意:Alex高中畢業了,他現在是大學新生。雖然他學習程式設計,但他還是要上體育課,這對他來說完全是一個意外。快要期末了,但是不幸的Alex的體育學分還是零蛋!
Alex可不希望被開除,他想知道到期末還有多少天的工作日,這樣他就能在這些日子裡修體育學分。但是在這裡計算工作日可不是件容易的事情:
從現在到學期結束還有 n 天(從 1 到 n 編號),他們一開始都是工作日。接下來學校的工作人員會依次發出 q 個指令,每個指令可以用三個引數 l,r,k 描述:
如果 k=1,那麼從 l 到 r (包含端點)的所有日子都變成非工作日。
如果 k=2,那麼從 l 到 r (包含端點)的所有日子都變成工作日。
幫助Alex統計每個指令下發後,剩餘的工作日天數
(1≤n≤10^9,1≤q≤3*10^5)
程式碼:
#include <map> #include <stack> #include <queue> #include <stack> #include <string> #include <vector> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; const int siz=15000005; int n,m,id; int ll[siz],rr[siz],sum[siz],lazy[siz]; void pushdown(int l,int r,int rt){ if(lazy[rt]!=-1){ int m=(l+r)>>1; if(l!=r){ //不是葉子節點則需要開闢左節點或右節點 if(ll[rt]==0) ll[rt]=++id; //從而把標記傳下去 if(rr[rt]==0) rr[rt]=++id; lazy[ll[rt]]=lazy[rt]; lazy[rr[rt]]=lazy[rt]; sum[ll[rt]]=(m-l+1)*lazy[rt]; sum[rr[rt]]=(r-m)*lazy[rt]; } lazy[rt]=-1; } } void change(int L,int R,int p,int l,int r,int &rt){ if(!rt) rt=++id; //動態開點就是什麼時候用什麼時候開點 if(L<=l&&r<=R){ lazy[rt]=p; sum[rt]=p*(r-l+1); return; } pushdown(l,r,rt); int m=(l+r)>>1; if(L<=m) change(L,R,p,l,m,ll[rt]); if(R>m) change(L,R,p,m+1,r,rr[rt]); sum[rt]=sum[ll[rt]]+sum[rr[rt]]; } int main(){ //因為n特別大,所以可以直接動態開點 int i,j,x,y,z,rt; //複雜度O(qlogn),複雜度可能沒有直接 while(scanf("%d%d",&n,&m)!=EOF){ //離散化O(qlogq)優秀,但是實現起來比較簡單 id=rt=0; memset(ll,0,sizeof(ll)); memset(rr,0,sizeof(rr)); memset(sum,0,sizeof(sum)); memset(lazy,-1,sizeof(lazy)); for(i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); if(z==1) change(x,y,1,1,n,rt); else change(x,y,0,1,n,rt); printf("%d\n",n-sum[1]); } } return 0; } /* 10 3 2 3 1 1 5 1 4 6 1 */