luogu題解 UVA11992 【Fast Matrix Operations】
阿新 • • 發佈:2018-04-29
per 最小值 int PE {} http type 和平 分別是
- 題目鏈接:
https://www.luogu.org/problemnew/show/UVA11992
- 題目大意:
一個r*c的矩陣,一開始元素都是0,然後給你m次三種操作,分別是將一個子矩陣中所有元素加上v,將一個子矩陣元素全部修改成v,詢問一個子矩陣中所有元素和,最大值和最小值.
- 思路:
應該說是一道有點毒瘤的數據結構題(然而時限居然給了5s)了,雖然它的主體只是線段樹。我們可以把每一行都看作一棵線段樹,這樣操作就十分方便了。
然後就是修改值的操作,對於初學者可能有點棘手,但實際上並不難,我們同樣可以用lazy_tag打標記。但是就有一些要註意的東西了,當我們打add(元素加值)標記時是不會影響set(修改值)標記的,但是我們在打set標記時無論你前面add標記是多少,此時就相當於作廢,所以直接將add標記賦為0就好了,然後直接修改sum,mi和mx(分別記錄該區間的和,最小值,最大值)。
同時我們可以讓query詢問函數直接返回一個存了sum,mi,mx的結構體,這樣就不用查三次了.
同時還有一個去要註意的地方,正如我們前面分析的那樣,每一行開一顆線段樹,但是實際上你真的不能搞一個tree[maxn],然後每一個tree中存一個線段樹的結構體,這樣是絕壁會爆的(我一開始就這麽搞),而是和平常一樣搞一個存全部元素的數組,具體怎麽做還請看代碼,我自認為還是寫的比較直觀。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cctype> #include <vector> using namespace std; const int maxn=1000005; const int inf=0xfffffff; int r,c,m,v; int L,R; struct Tmp{ Tmp() : sum(0), mx(-inf),mi(inf) {}//構造函數,非常方便,強烈推薦 Tmp(int x,int y,int z) :sum(x),mx(y),mi(z) {} int sum; int mx,mi; };//query詢問時直接返回這個結構體就好了 int sum[maxn<<2],add[maxn<<2],set[maxn<<2],mx[maxn<<2],mi[maxn<<2]; inline void up(int now){ sum[now]=sum[now<<1]+sum[now<<1|1]; mx[now]=max(mx[now<<1],mx[now<<1|1]); mi[now]=min(mi[now<<1],mi[now<<1|1]); return ; } void build(int now,int l,int r){//其實build一點用也沒有,請大家忽略 if(l==r){ mx[now]=0;//-inf; mi[now]=0;//inf; return ; } int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); up(now); return ; } inline void down(int now,int ln,int rn){//註意看這個push_down函數 if(set[now]){//修改標記 sum[now<<1]=set[now]*ln; sum[now<<1|1]=set[now]*rn; set[now<<1]=set[now]; set[now<<1|1]=set[now]; add[now<<1]=add[now<<1|1]=0; mx[now<<1]=mx[now<<1|1]=set[now]; mi[now<<1]=mi[now<<1|1]=set[now]; set[now]=0; } if(add[now]){//加值標記 sum[now<<1]+=add[now]*ln; sum[now<<1|1]+=add[now]*rn; add[now<<1]+=add[now]; add[now<<1|1]+=add[now]; mx[now<<1]+=add[now]; mi[now<<1]+=add[now]; mx[now<<1|1]+=add[now]; mi[now<<1|1]+=add[now]; add[now]=0; } return ; } void update_add(int now,int l,int r){ if(L<=l&&r<=R){ add[now]+=v; sum[now]+=v*(r-l+1); mx[now]+=v; mi[now]+=v; return ; } int mid=(l+r)>>1; down(now,mid-l+1,r-mid); if(L<=mid)update_add(now<<1,l,mid); if(mid<R)update_add(now<<1|1,mid+1,r); up(now); return ; } void update_set(int now,int l,int r){ if(L<=l&&r<=R){ set[now]=v; sum[now]=v*(r-l+1); add[now]=0; mx[now]=v; mi[now]=v; return ; } int mid=(l+r)>>1; down(now,mid-l+1,r-mid); if(L<=mid)update_set(now<<1,l,mid); if(mid<R)update_set(now<<1|1,mid+1,r); up(now); return ; } Tmp query(int now,int l,int r){ if(L<=l&&r<=R){ return Tmp(sum[now],mx[now],mi[now]);//十分方便 } int mid=(l+r)>>1; down(now,mid-l+1,r-mid); Tmp tmp; int sum=0,mx=-inf,mi=inf; if(L<=mid){ tmp=query(now<<1,l,mid); sum+=tmp.sum; mx=max(mx,tmp.mx); mi=min(mi,tmp.mi); } if(mid<R){ tmp=query(now<<1|1,mid+1,r); sum+=tmp.sum; mx=max(mx,tmp.mx); mi=min(mi,tmp.mi); } // up(now); //然而並不用up() tmp.sum=sum,tmp.mi=mi,tmp.mx=mx; return tmp; } template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c==‘-‘; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x; return ; } int main() { int op,x1,x2,y1,y2; read(r),read(c),read(m); // build(1,1,r*c); while(m--){ read(op),read(x1),read(y1),read(x2),read(y2); if(op==1){ read(v); for(register int i=x1;i<=x2;i++){ L=(i-1)*c+y1,R=(i-1)*c+y2; //註意處理技巧!!! update_add(1,1,r*c); //r*c是所有元素的範圍 } } else if(op==2){ read(v); for(register int i=x1;i<=x2;i++){ L=(i-1)*c+y1,R=(i-1)*c+y2; //註意處理技巧!!! update_set(1,1,r*c); } } else { Tmp tmp; int sum=0,mx=-inf,mi=inf; for(register int i=x1;i<=x2;i++){ L=(i-1)*c+y1,R=(i-1)*c+y2; //註意處理技巧!!! tmp=query(1,1,r*c); sum+=tmp.sum; mx=max(mx,tmp.mx); mi=min(mi,tmp.mi); } printf("%d %d %d\n",sum,mi,mx); } } return 0; }
luogu題解 UVA11992 【Fast Matrix Operations】