luogu P3722 [AH2017/HNOI2017]影魔
阿新 • • 發佈:2022-05-29
題面傳送門
線段樹是什麼勾八玩意兒。
看到題一頭霧水,然後看了看部分分,有個奇怪的\(p1=2p2\)。
略微撕烤一下這檔分怎麼做,大概就是第一種貢獻可以看作兩個第二個貢獻的疊加。
於是我們可以把題意轉化一下:
第一種貢獻:如果一個區間\([l,r]\),滿足\(a_r\)大於\([l+1,r-1]\)最大值,那麼貢獻\(p2\),如果\(a_l\)也是這樣,疊加貢獻\(p2\)。
第二種貢獻:如果一個區間\([l,r]\),滿足\(a_r,a_l\)均大於區間中的數,那麼貢獻\(p1-2p2\)
第一種貢獻顯然是可算的,直接單調棧然後掃描線,第二種貢獻看上去就不是那麼可做。
證明一個結論:造成第二種貢獻的區間個數是\(O(n)\)
考慮掃描線維護單調棧的過程,如果\(a_i\)與前面的一個\(a_l\)構成了上面這種區間,要麼\(a_l>a_i\),這對每個數來說停止彈棧,是\(O(n)\)的,第二種是\(a_l<a_i\),那麼接下來\(a_l\)被彈出,也是\(O(n)\)的,所以這個貢獻在掃描線的時候暴力修改就好了。
時間複雜度\(O(n\log n)\),寫了個樹狀陣列才跑起來像個log樣。
code:
#include<bits/stdc++.h> #define I inline #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define abs(x) ((x)>0?(x):-(x)) #define ll long long #define db double #define lb long db #define N (200000+5) #define M ((N<<2)+5) #define Ks (12+5) #define mod 1000000007 #define Mod (mod-1) #define eps (1e-9) #define ull unsigned ll #define it iterator #define Gc() getchar() #define Me(x,y) memset(x,y,sizeof(x)) #define Mc(x,y) memcpy(x,y,sizeof(x)) #define d(x,y) (n*(x-1)+(y)) #define R(n) (1ll*rand()*rand()%(n)+1) #define Pc(x) putchar(x) #define LB lower_bound #define UB upper_bound #define PB push_back using namespace std;struct Ques{int w,id;};vector<Ques> S[N]; int n,m,k,L[N],R[N],X[N],Y[N],z,p1,p2,st[N],H,A[N];ll Ans[N]; namespace Tree{ ll F1[N],F2[N];I void I1(int x,int y){while(x<=n) F1[x]+=y,x+=x&-x;}I void I2(int x,int y){while(x<=n) F2[x]+=y,x+=x&-x;} I ll Q1(int x){ll Ans=0;while(x) Ans+=F1[x],x-=x&-x;return Ans;}I ll Q2(int x){ll Ans=0;while(x) Ans+=F2[x],x-=x&-x;return Ans;} I void Ins(int x,int y,int z){I1(x,z);I2(x,z*(x-1));I1(y+1,-z);I2(y+1,-z*y);} I ll Qry(int x,int y){return Q1(y)*y-Q2(y)-Q1(x-1)*(x-1)+Q2(x-1);} } int main(){ freopen("1.in","r",stdin); int i,j;scanf("%d%d%d%d",&n,&m,&p1,&p2);for(i=1;i<=n;i++) scanf("%d",&A[i]),L[i]=0,R[i]=n+1;H=0;for(i=1;i<=n;i++) {while(H&&A[st[H]]<A[i]) R[st[H--]]=i;L[i]=st[H];st[++H]=i;} for(i=1;i<=m;i++) scanf("%d%d",&X[i],&Y[i]),S[Y[i]].PB((Ques){X[i],i});H=0;for(i=1;i<=n;i++){ Tree::Ins(max(L[i],1),i-1,p2);while(H&&A[st[H]]<A[i]) Tree::Ins(st[H],st[H],p1-2*p2),H--;H&&(Tree::Ins(st[H],st[H],p1-2*p2),0);st[++H]=i;for(Ques d:S[i]) Ans[d.id]=Tree::Qry(d.w,i); }for(i=1;i<=n;i++) S[i].clear();for(i=1;i<=m;i++) S[X[i]].PB((Ques){Y[i],i});Me(Tree::F1,0);Me(Tree::F2,0); for(i=n;i;i--){Tree::Ins(i+1,min(n,R[i]),p2);for(Ques d:S[i]) Ans[d.id]+=Tree::Qry(i,d.w);} for(i=1;i<=m;i++) printf("%lld\n",Ans[i]); }