BZOJ_4636_蒟蒻的數列_線段樹+動態開點
阿新 • • 發佈:2018-05-20
desc mes bound d+ lib scan 他還 inpu AI
2 5 1
9 10 4
6 8 2
4 6 3
把操作離線並從小到大排序,相當於線段樹維護區間賦值操作。 本題可以離散化也可以動態開點,我這裏處理不好線段樹維護離散後的區間因此寫了動態開點。 註意pushdown操作時如果沒有這個兒子也要開出來。 代碼:
BZOJ_4636_蒟蒻的數列_線段樹+動態開點
Description
蒟蒻DCrusher不僅喜歡玩撲克,還喜歡研究數列 題目描述 DCrusher有一個數列,初始值均為0,他進行N次操作,每次將數列[a,b)這個區間中所有比k小的數改為k,他想知 道N次操作後數列中所有元素的和。他還要玩其他遊戲,所以這個問題留給你解決。Input
第一行一個整數N,然後有N行,每行三個正整數a、b、k。 N<=40000 , a、b、k<=10^9Output
一個數,數列中所有元素的和Sample Input
42 5 1
9 10 4
6 8 2
Sample Output
16把操作離線並從小到大排序,相當於線段樹維護區間賦值操作。 本題可以離散化也可以動態開點,我這裏處理不好線段樹維護離散後的區間因此寫了動態開點。 註意pushdown操作時如果沒有這個兒子也要開出來。 代碼:
#include <stdio.h> #include <string.h> #include <algorithm> #include <stdlib.h> using namespace std; #define N 40050 #define maxn 1000000000 typedef long long ll; struct A { int l,r,k; }a[N]; bool cmp(const A &x,const A &y) {return x.k<y.k;} int tag[N*80],cnt,n,ls[N*80],rs[N*80]; ll t[N*80]; /*int make(int x) { return lower_bound(v+1,v+cnt+1,x)-v; }*/ void pushdown(int l,int r,int &p,int w) { if(!p) p=++cnt; t[p]=1ll*w*(r-l+1); tag[p]=w; } void update(int l,int r,int x,int y,int w,int &p) { if(p==0) p=++cnt; if(x<=l&&y>=r) { t[p]=1ll*w*(r-l+1); tag[p]=w; return ; } int mid=(l+r)>>1; if(tag[p]) { pushdown(l,mid,ls[p],tag[p]); pushdown(mid+1,r,rs[p],tag[p]); tag[p]=0; } if(x<=mid) update(l,mid,x,y,w,ls[p]); if(y>mid) update(mid+1,r,x,y,w,rs[p]); t[p]=t[ls[p]]+t[rs[p]]; } int main() { scanf("%d",&n); int i; for(i=1;i<=n;i++) { scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].k); a[i].r--; /*v[++cnt]=a[i].l; v[++cnt]=a[i].r;*/ } /*sort(v+1,v+cnt+1); cnt=unique(v+1,v+cnt+1)-v-1; printf("%d\n",cnt); for(i=1;i<=cnt;i++) printf("%d\n",v[i]); */ sort(a+1,a+n+1,cmp); int root=0; for(i=1;i<=n;i++) { if(a[i].k==0) continue; /*printf("%d %d\n",make(a[i].l),make(a[i].r)); update(1,cnt,make(a[i].l),make(a[i].r),a[i].k,1); printf("sum=%lld\n",t[1]);*/ update(1,maxn,a[i].l,a[i].r,a[i].k,root); } printf("%lld\n",t[1]); }
BZOJ_4636_蒟蒻的數列_線段樹+動態開點