我們考慮從左往右掃右端點和從右往左掃左端點的兩遍掃瞄線。(以下選取從左往右的掃瞄線來說明)考慮每個點向它左邊第乙個比它大的點連邊形成的樹。設i左邊第乙個比它大的點的座標是la
sti (如果沒有則la
sti=
0 ),i右邊第乙個比它大的點的座標是ne
xti (如果沒有則ne
xti=
n+1 )。設[l,r]的最小值的座標是x,則從r到x的路徑上的點y的貢獻是ay
∗(y−
last
i)∗(
r−y+
1)(不包括x,x單獨算),被[l,r]完全包含的子樹y的貢獻是ay
∗(y−
last
y)∗(
next
y−y)
,這兩個顯然是都可以字首和出來的。我們只需要用棧維護當前節點的祖先們,然後二分找到最接近左端點的即可。
乙個需要注意的地方是,為了保證區間最小值是一樣的,從左往右和從右往左時樹的形態要是不同的。比如說從左往右掃時,乙個點的父親是它左邊第乙個小於它的點,那麼從右往左掃時乙個點的父親就應該是它右邊第乙個小於等於它的點。
**:
#include
#include
using
namespace
std;
#include
#include
const
int n=1e5+5,q=1e5+5;
typedef
long
long ll;
int n;
ll a[n];
void in(int &x)
void in(ll &x)
intstack[n],top;
ll s0[n],s1[n],s2[n];
struct qsque[q];
ll ans[q];
bool cmp0(const qs &a,const qs &b)
int main()
//couts1[top]=s1[top-1]+a[i]*(i-stack[top-1]);
s2[top]=tmp;
stack[top]=i;
//for(int k=1;k<=top;++k)printf("%d:%i64d,%i64d,%i64d\n",stack[k],s0[k],s1[k],s2[k]);
for(;que[j].r==i;++j)
++top;
}sort(que,que+q,cmp1);
stack[0]=n+1;
top=1;
tmp=0;
for(int i=n,j=0;i;--i)
ans[que[j].i]+=(s2[top]-s2[r])+((s0[top]-s0[r])-(s1[top]-s1[r])*i)+a[stack[r]]*(que[j].r-stack[r]+1)*(stack[r]-que[j].l+1);
//cout}
++top;
}for(int i=0;iprintf("%i64d\n",ans[i]);
}
總結:
①大資料拍不出錯,小資料說不定一拍就錯!
②笛卡爾樹的題目中相等情況一定要考慮清楚。
題解 HNOI 2016序列
collapse bzoj 這道題在hnoi2016中還算是好的了 這題中如若去掉多組詢問的話可以在o nlogn o n log n 的時間內得解 並查集 但多組詢問必定要優化,發現這種其他結構基本上無法涉足的題目就只能上莫隊了 我也不知道為啥想到莫隊,可能這就是題感吧 減去o nn o n n ...
HNOI2016 序列(未通過)
題解 雖然知道有點問題但是並沒有debug出來 發現錯誤了。相同元素的處理有錯誤 網上題解大都是分塊。hn怎麼道道分塊 用最普通的思路,可以列舉每個點作為最小值,向左向右延伸 但是多組詢問顯然我們是要去優化詢問過程的 有一種方法就是先找出最大值 其實也可以是隨意乙個位置吧,但yy一下應該最大值能擴充...
Hnoi2016 序列(莫隊 st表)
給定長度為 n n 的序列 a1 role presentation style position relative a1a 1,a2 a 2,an a n,記為a 1 n a 1 n 類似地,a l r a l r 1 l r n 1 l r n 是指序列 al a l,al 1a l 1,ar ...