題解 P3373 模板 線段樹 2

2022-04-08 01:19:23 字數 3294 閱讀 7556

好丟臉,這個題做了一下午,除錯了三個多小時......

既然這裡是線段樹,就要用到lazy—tag。又有加法又有乘法的話,就要用到兩個lazy-tag,分別用陣列jia和chng表示。線段樹用陣列t存。

我們讓lazy-tag還原數值時,先乘chng,再加jia(人為規定,這樣好算)

怎麼維護lazy-tag?

加法void add( k, l, r, x, y, delta)

long long mid=(l+r)>>1;

pushdown(k,l,r);

if(x>=mid+1) add(k*2+1,mid+1,r,x,y,delta);

else if(y<=mid) add(k*2,l,mid,x,y,delta);

else

t[k]=t[k*2]+t[k*2+1];

t[k]%=p;

}乘法void cheng(k,l,r,x,y,ch)

**

void cheng(long long k, long long l, long long r, long long x, long long y, long long ch)

pushdown(k,l,r);

long long mid=(l+r)>>1;

if(x>=mid+1) cheng(k*2+1,mid+1,r,x,y,ch);

else if(y<=mid) cheng(k*2,l,mid,x,y,ch);

else

t[k]=t[k*2]+t[k*2+1];

t[k]%=p;

}

pushdown

維護lazy-tag需要pushdown,詢問輸出也要pushdown

pushdown是標記下傳操作,意味著當前樹k不再保留所在區間的加乘標記,也就是說,pushdown後,jia[k]=0,chng[k]=1。

下傳到子樹時,子樹的加、乘標記和本身的值都要改變(終於不是憨憨的啥也不知道了!)。

void pushdown(k,l,r)

this is the code

void pushdown(long long k, long long l, long long r)

long long mid=(l+r)>>1;

build(k*2,l,mid);

build(k*2+1,mid+1,r);//遞迴建樹

t[k]=(t[k*2]+t[k*2+1])%p;//給父親賦值

}

詢問

void query(k,l,r,x,y)

code

long long query(long long k, long long l, long long r, long long x, long long y)

pushdown(k,l,r);

long long mid = (l+r)>>1;

if(x>=mid+1) return query(k*2+1,mid+1,r,x,y)%p;

else if(y<=mid) return query(k*2,l,mid,x,y)%p;

else return (query(k*2,l,mid,x,mid)+query(k*2+1,mid+1,r,mid+1,y))%p;

}

這樣這個題大體就成了,然鵝,想要ac,還要注意以下三點

1.陣列開多大?其實要開n4,開n3也過了,但是開n*2就不行

2.開longlong!開longlong!!

3.隨時取模,query返回時也要再取模

**

#include #include #include #include #include #include #include #define n 100100

//開longlong

//開4倍

using namespace std;

long long n,m,x,y,k,p,a[n],jia[n*4],chng[n*4],t[n*4];//開4倍

void build(long long k, long long l, long long r)

long long mid=(l+r)>>1;

build(k*2,l,mid);

build(k*2+1,mid+1,r);

t[k]=(t[k*2]+t[k*2+1])%p;

}void pushdown(long long k, long long l, long long r)

void add(long long k, long long l, long long r, long long x, long long y, long long delta)

long long mid=(l+r)>>1;

pushdown(k,l,r);

if(x>=mid+1) add(k*2+1,mid+1,r,x,y,delta);

else if(y<=mid) add(k*2,l,mid,x,y,delta);

else

t[k]=t[k*2]+t[k*2+1]; t[k]%=p;

}void cheng(long long k, long long l, long long r, long long x, long long y, long long ch)

pushdown(k,l,r);

long long mid=(l+r)>>1;

if(x>=mid+1) cheng(k*2+1,mid+1,r,x,y,ch);

else if(y<=mid) cheng(k*2,l,mid,x,y,ch);

else

t[k]=t[k*2]+t[k*2+1]; t[k]%=p;

}long long query(long long k, long long l, long long r, long long x, long long y)

pushdown(k,l,r);

long long mid = (l+r)>>1;

if(x>=mid+1) return query(k*2+1,mid+1,r,x,y)%p;

else if(y<=mid) return query(k*2,l,mid,x,y)%p;

else return (query(k*2,l,mid,x,mid)+query(k*2+1,mid+1,r,mid+1,y))%p;

}int main()

if(tt==2)

if(tt==3)

} return 0;

}

P3373 模板 線段樹2

如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 include include using namespace std const int maxn 100005 int n,m,p long long arr maxn...

P3373 模板 線段樹 2

ac 這裡的延遲標記要開兩個,分別記錄加法的值和乘法的值,但是乘法和加法的優先順序不一樣,不規定他們的順序的話會有錯誤,所以可以規定乘法優先,即規定好該結點的值等於該節點的值 父節點的乘法延遲標記的值 父節點加法延遲標記的值 區間長度,即,sum num 2 sum num 2 add num wc...

P3373 模板 線段樹 2

題目描述 如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 輸入格式 第一行包含三個整數n m p,分別表示該數列數字的個數 操作的總個數和模數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來...