CodeVS 4927-線段樹練習5
阿新 • • 發佈:2017-09-10
include ostream pro .cn pushd poi 之前 ios mil
題目&之前寫過的題解
題解
這是我第二次寫這道題了,也是我轉語言之後寫的第一次。
首先要明確一點,不讓一個節點同時擁有兩個懶標記(delta,set),並且set的優先級比delta大,接著就好辦了。
於是你會發現,每個子程序的第一句話都是下傳set標記。每次下傳都要將該點的sum/max/min值計算一遍。
代碼:
#include<cmath> #include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #define INF 10000000 #define ll long long using namespace std; ll n,m,x,y,z; char ch[5]; struct poi{int l,r;ll sum,delta,set,max,min;bool bn;} a[800010]; ll calcsum(int x) {return a[x].bn? a[x].set*(a[x].r-a[x].l+1):a[x].sum+a[x].delta*(a[x].r-a[x].l+1);} ll calcmax(int x) {return a[x].bn? a[x].set:a[x].max+a[x].delta;} ll calcmin(int x) {return a[x].bn? a[x].set:a[x].min+a[x].delta;} void calc(int x) { a[x].sum=calcsum(x<<1)+calcsum(x<<1|1); a[x].max=max(calcmax(x<<1),calcmax(x<<1|1)); a[x].min=min(calcmin(x<<1),calcmin(x<<1|1)); } void pushdownset(int x) { a[x<<1].bn=a[x<<1|1].bn=1;a[x<<1].set=a[x<<1|1].set=a[x].set;a[x<<1].delta=a[x<<1|1].delta=0; a[x].sum=calcsum(x);a[x].max=calcmax(x);a[x].min=calcmin(x);a[x].bn=0; } void pushdowndelta(int x) { if (a[x<<1].bn) pushdownset(x<<1);if (a[x<<1|1].bn) pushdownset(x<<1|1); a[x<<1].delta+=a[x].delta;a[x<<1|1].delta+=a[x].delta; a[x].sum=calcsum(x);a[x].max=calcmax(x);a[x].min=calcmin(x);a[x].delta=0; } void build(int x,int l,int r) { a[x].l=l; a[x].r=r; if (l==r) {scanf("%lld",&a[x].sum); a[x].max=a[x].min=a[x].sum; return;} build(x<<1,l,(l+r)>>1); build(x<<1|1,((l+r)>>1)+1,r); calc(x); } void delta(int x,int l,int r,ll del) { if (a[x].bn) pushdownset(x); if (a[x].l>=l && a[x].r<=r) {a[x].delta+=del; return;} if (a[x].delta) pushdowndelta(x); if (l<=(a[x].l+a[x].r)>>1) delta(x<<1,l,r,del); if (r>(a[x].l+a[x].r)>>1) delta(x<<1|1,l,r,del); calc(x); } void set(int x,int l,int r,ll s) { if (a[x].bn) pushdownset(x); if (a[x].l>=l && a[x].r<=r) {a[x].bn=1; a[x].set=s; a[x].delta=0; return;} if (a[x].delta) pushdowndelta(x); if (l<=(a[x].l+a[x].r)>>1) set(x<<1,l,r,s); if (r>(a[x].l+a[x].r)>>1) set(x<<1|1,l,r,s); calc(x); } ll querysum(int x,int l,int r) { ll ret=0; if (a[x].bn) pushdownset(x); if (a[x].l>=l && a[x].r<=r) return calcsum(x); if (a[x].delta) pushdowndelta(x); if (l<=(a[x].l+a[x].r)>>1) ret+=querysum(x<<1,l,r); if (r>(a[x].l+a[x].r)>>1) ret+=querysum(x<<1|1,l,r); return ret; } ll querymax(int x,int l,int r) { ll ret=-INF; if (a[x].bn) pushdownset(x); if (a[x].l>=l && a[x].r<=r) return calcmax(x); if (a[x].delta) pushdowndelta(x); if (l<=(a[x].l+a[x].r)>>1) ret=max(ret,querymax(x<<1,l,r)); if (r>(a[x].l+a[x].r)>>1) ret=max(ret,querymax(x<<1|1,l,r)); return ret; } ll querymin(int x,int l,int r) { ll ret=INF; if (a[x].bn) pushdownset(x); if (a[x].l>=l && a[x].r<=r) return calcmin(x); if (a[x].delta) pushdowndelta(x); if (l<=(a[x].l+a[x].r)>>1) ret=min(ret,querymin(x<<1,l,r)); if (r>(a[x].l+a[x].r)>>1) ret=min(ret,querymin(x<<1|1,l,r)); return ret; } main() { scanf("%lld%lld",&n,&m); build(1,1,n); for (int i=1; i<=m; i++) { scanf("%s",ch); if (ch[0]==‘a‘) {scanf("%lld%lld%lld",&x,&y,&z); delta(1,x,y,z);} if (ch[1]==‘e‘) {scanf("%lld%lld%lld",&x,&y,&z); set(1,x,y,z);} if (ch[1]==‘u‘) {scanf("%lld%lld",&x,&y); printf("%lld\n",querysum(1,x,y));} if (ch[1]==‘a‘) {scanf("%lld%lld",&x,&y); printf("%lld\n",querymax(1,x,y));} if (ch[1]==‘i‘) {scanf("%lld%lld",&x,&y); printf("%lld\n",querymin(1,x,y));} } return 0; }
CodeVS 4927-線段樹練習5