<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【做題記錄】csp2025-提高組生成樹和笛卡爾樹專題

      A. [COCI2009-2010#7] SVEMIR

      顯然 boruvka。將所有點(diǎn)分別按照 \(x\)\(y\)\(z\) 排序,更新最小邊。時(shí)間復(fù)雜度 \(O(n\log^2 n)\)

      Code
      #include<cstdio>
      #include<iostream>
      #include<utility>
      #include<algorithm>
      #include<climits>
      #define ll long long
      #define il inline
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+5;
      int n,fa[maxn],sz[maxn];
      pii mne[maxn];
      struct node{
      	int x,y,z,id;
      }a[maxn];
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      il void merge(int u,int v){
      	u=find(u),v=find(v);
      	if(u==v){
      		return ;
      	}
      	if(sz[u]>sz[v]){
      		sz[u]+=sz[v],fa[v]=u;
      	}
      	else{
      		sz[v]+=sz[u],fa[u]=v;
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n;
      	for(int i=1;i<=n;i++){
      		cin>>a[i].x>>a[i].y>>a[i].z;
      		a[i].id=fa[i]=i,sz[i]=1;
      	}
      	ll ans=0;
      	for(;;){
      //		puts("666");
      		for(int i=1;i<=n;i++){
      			mne[i]=mp(INT_MAX,0);
      		}
      		sort(a+1,a+n+1,[](const node &p,const node &q){return p.x<q.x;});
      		for(int i=1,u,v,w;i<n;i++){
      			u=find(a[i].id),v=find(a[i+1].id),w=a[i+1].x-a[i].x;
      			if(u!=v){
      				mne[u]=min(mne[u],mp(w,v));
      				mne[v]=min(mne[v],mp(w,u));
      			}
      		}
      		sort(a+1,a+n+1,[](const node &p,const node &q){return p.y<q.y;});
      		for(int i=1,u,v,w;i<n;i++){
      			u=find(a[i].id),v=find(a[i+1].id),w=a[i+1].y-a[i].y;
      			if(u!=v){
      				mne[u]=min(mne[u],mp(w,v));
      				mne[v]=min(mne[v],mp(w,u));
      			}
      		}
      		sort(a+1,a+n+1,[](const node &p,const node &q){return p.z<q.z;});
      		for(int i=1,u,v,w;i<n;i++){
      			u=find(a[i].id),v=find(a[i+1].id),w=a[i+1].z-a[i].z;
      			if(u!=v){
      				mne[u]=min(mne[u],mp(w,v));
      				mne[v]=min(mne[v],mp(w,u));
      			}
      		}
      		bool flag=0;
      		for(int i=1;i<=n;i++){
      			if(find(i)==i&&mne[i].fir<INT_MAX&&find(i)!=find(mne[i].sec)){
      				flag=1;
      				merge(i,mne[i].sec);
      				ans+=mne[i].fir;
      			}
      		}
      		if(!flag){
      			break;
      		}
      	}
      	cout<<ans;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      B. [SCOI2012] 滑雪

      對于第一問,按照高度決定連邊方向,跑個(gè) bfs 即可。
      對于第二問,顯然 prim 可做。但是在優(yōu)先隊(duì)列內(nèi),需要按照點(diǎn)的高度從大到小為第一關(guān)鍵字,距離從小到大為第二關(guān)鍵字。原因是我們建的是一張有向圖,有些邊從較低的點(diǎn)向較高的點(diǎn)是更新不到的。而如果依次考慮由高向低的點(diǎn),則一定可以保證每條邊都被考慮到,且考慮到每個(gè)點(diǎn)時(shí)指向它的邊一定已經(jīng)被考慮完了。時(shí)間復(fù)雜度 \(O(m\log n)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      #define pb push_back
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+5,maxm=1e6+5;
      int n,m,a[maxn],fa[maxn],sz[maxn];
      ll dis[maxn];
      bool vis[maxn],viss[maxn];
      vector<pii> e[maxn];
      queue<int> q;
      struct cmp{
      	il bool operator()(const pii &x,const pii &y)const{
      		if(a[x.sec]!=a[y.sec]){
      			return a[x.sec]<a[y.sec];
      		}
      		return x.fir>y.fir;
      	}
      };
      priority_queue<pii,vector<pii>,cmp> p;
      struct node{
      	int u,v,w;
      	il bool operator<(const node &x)const{
      		return w<x.w;
      	}
      }ed[maxm<<1];
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      il void merge(int u,int v){
      	u=find(u),v=find(v);
      	if(u==v){
      		return ;
      	}
      	if(sz[u]>sz[v]){
      		sz[u]+=sz[v],fa[v]=u;
      	}
      	else{
      		sz[v]+=sz[u],fa[u]=v;
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      //	cout<<cplx::usdmem();
      	cin>>n>>m;
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      		fa[i]=i,sz[i]=1;
      	}
      	for(int i=1,u,v,w;i<=m;i++){
      		cin>>u>>v>>w;
      		if(a[u]>=a[v]){
      			e[u].pb(mp(v,w));
      		}
      		if(a[v]>=a[u]){
      			e[v].pb(mp(u,w));
      		}
      	}
      	int ans1=0;
      	q.push(1),vis[1]=1;
      	while(q.size()){
      		int u=q.front();
      		ans1++,q.pop();
      		for(pii i:e[u]){
      			int v=i.fir;
      			if(!vis[v]){
      				q.push(v),vis[v]=1;
      			}
      		}
      	}
      	memset(dis,0x3f,sizeof dis);
      	dis[1]=0,p.push(mp(0,1));
      	while(p.size()){
      		int u=p.top().sec;
      //		cout<<u<<"\n";
      		p.pop(),viss[u]=1;
      		for(pii i:e[u]){
      			int v=i.fir,w=i.sec;
      			if(!vis[v]){
      				continue;
      			}
      			if(!viss[v]&&dis[v]>w){
      				dis[v]=w;
      				p.push(mp(w,v));
      			}
      		}
      	}
      	ll ans2=0;
      	for(int i=1;i<=n;i++){
      		if(vis[i]){
      			ans2+=dis[i];
      		}
      	}
      	cout<<ans1<<" "<<ans2;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      C. [USACO01OPEN] Earthquake

      \[\begin{aligned} &ans=\frac{f-\sum_{i\in S}c_i}{\sum_{i\in S}t_i}\\ \Leftrightarrow&f=\sum_{i\in S}t_i\times ans+c_i \end{aligned} \]

      其中 \(S\) 為最終選擇的邊集。
      則對于任意一個(gè)生成樹 \(K\) 我們有:

      \[\begin{aligned} &ans\ge\frac{f-\sum_{i\in K}c_i}{\sum_{i\in K}t_i}\\ \Leftrightarrow&f\le \sum_{i\in K}t_i\times ans+c_i \end{aligned} \]

      于是對于任意實(shí)數(shù) \(x\),考慮它與 \(ans\) 的大小關(guān)系:

      • \(x>ans\)
        \(\forall K,f<\sum_{i\in K}t_i\times x+c_i\)
      • \(x=ans\)
        \(\forall K,f\le\sum_{i\in K}t_i\times x+c_i\)
      • \(x<ans\)
        \(\exist K,f>\sum_{i\in K}t_i\times x+c_i\)

      于是二分答案,跑最小生成樹 check 即可。時(shí)間復(fù)雜度 \(O(m\log^2)\)
      因?yàn)檩敵鲆缶_到小數(shù)點(diǎn)后第 \(4\) 位,所以要求二分出來的答案精確到小數(shù)點(diǎn)后第 \(5\) 位,所以 \(\varepsilon\) 應(yīng)該賦為 \(10^{-6}\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=405,maxm=1e4+5;
      const double eps=1e-6;
      int n,m,f,fa[maxn],sz[maxn];
      struct node{
      	int u,v,c,t;
      }e[maxm];
      il int find(int x){
      	return fa[x]!=x?fa[x]=find(fa[x]):x;
      }
      il void merge(int u,int v){
      	u=find(u),v=find(v);
      	if(u==v){
      		return ;
      	}
      	if(sz[u]>sz[v]){
      		sz[u]+=sz[v],fa[v]=u;
      	}
      	else{
      		sz[v]+=sz[u],fa[u]=v;
      	}
      }
      il double kruskal(double x){
      	sort(e+1,e+m+1,[=](const node &p,const node &q){return p.t*x+p.c<q.t*x+q.c;});
      	for(int i=1;i<=n;i++){
      		fa[i]=i,sz[i]=1;
      	}
      	double res=0;
      	for(int i=1,u,v;i<=m;i++){
      		u=e[i].u,v=e[i].v;
      		if(find(u)!=find(v)){
      			merge(u,v);
      			res+=e[i].t*x+e[i].c;
      		}
      	}
      //	cout<<res<<"\n";
      	return res;
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>f;
      	for(int i=1;i<=m;i++){
      		cin>>e[i].u>>e[i].v>>e[i].c>>e[i].t;
      	}
      	double l=0,r=1e14;
      	while(r-l>eps){
      		double mid=(l+r)/2;
      //		cout<<mid<<" ";
      		if(kruskal(mid)>=f){
      			r=mid;
      		}
      		else{
      			l=mid;
      		}
      	}
      	printf("%.4f",l);
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      D. [藍(lán)橋杯 2023 省 A] 網(wǎng)絡(luò)穩(wěn)定性

      建出最大生成樹,然后樹剖 \(+\) 線段樹鏈查詢最小值即可。時(shí)間復(fù)雜度 \(O(q\log^2n)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      #define pb push_back
      #define lid id<<1
      #define rid id<<1|1
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+5,inf=0x3f3f3f3f;
      int n,m,q,fa[maxn],sz[maxn],dis[maxn];
      int dep[maxn],hes[maxn],top[maxn];
      int dfn[maxn],idx[maxn],cnt,tr[maxn<<2];
      struct node{
      	int u,v,w;
      	il bool operator<(const node &x)const{
      		return w>x.w;
      	}
      }a[maxn*3];
      vector<pii> e[maxn];
      struct{
      	int fa[maxn],sz[maxn];
      	il void init(){
      		for(int i=1;i<=n;i++){
      			fa[i]=i,sz[i]=1;
      		}
      	}
      	il int find(int x){
      		return x!=fa[x]?fa[x]=find(fa[x]):x;
      	}
      	il void merge(int u,int v){
      		u=find(u),v=find(v);
      		if(u==v){
      			return ;
      		}
      		if(sz[u]>sz[v]){
      			sz[u]+=sz[v],fa[v]=u;
      		}
      		else{
      			sz[v]+=sz[u],fa[u]=v;
      		}
      	}
      	il bool check(int u,int v){
      		return find(u)==find(v);
      	}
      }D;
      il void dfs1(int u){
      	dep[u]=dep[fa[u]]+1;
      	sz[u]=1;
      	int mxs=0;
      	for(pii i:e[u]){
      		int v=i.fir,w=i.sec;
      		if(v==fa[u]){
      			continue;
      		}
      		fa[v]=u,dis[v]=w;
      		dfs1(v);
      		sz[u]+=sz[v];
      		if(mxs<sz[v]){
      			mxs=sz[v],hes[u]=v;
      		}
      	}
      }
      il void dfs2(int u){
      	dfn[u]=++cnt;
      	idx[cnt]=u;
      	if(!top[u]){
      		top[u]=u;
      	}
      	if(hes[u]){
      		top[hes[u]]=top[u];
      		dfs2(hes[u]);
      	}
      	for(pii i:e[u]){
      		int v=i.fir;
      		if(v!=fa[u]&&v!=hes[u]){
      			dfs2(v);
      		}
      	}
      }
      il void pushup(int id){
      	tr[id]=min(tr[lid],tr[rid]);
      }
      il void build(int id,int l,int r){
      	if(l==r){
      		tr[id]=dis[idx[l]];
      		return ;
      	}
      	int mid=(l+r)>>1;
      	build(lid,l,mid);
      	build(rid,mid+1,r);
      	pushup(id);
      }
      il int query(int id,int L,int R,int l,int r){
      	if(l>r){
      		return inf;
      	}
      	if(L>=l&&R<=r){
      		return tr[id];
      	}
      	int mid=(L+R)>>1,res=inf;
      	if(l<=mid){
      		res=min(res,query(lid,L,mid,l,r));
      	}
      	if(r>mid){
      		res=min(res,query(rid,mid+1,R,l,r));
      	}
      	return res;
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>q;
      	for(int i=1;i<=m;i++){
      		cin>>a[i].u>>a[i].v>>a[i].w;
      	}
      	sort(a+1,a+m+1);
      	D.init();
      	for(int i=1,u,v,w;i<=m;i++){
      		u=a[i].u,v=a[i].v,w=a[i].w;
      		if(D.find(u)!=D.find(v)){
      			D.merge(u,v);
      			e[u].pb(mp(v,w));
      			e[v].pb(mp(u,w));
      		}
      	}
      	for(int i=1;i<=n;i++){
      		if(!dep[i]){
      			dfs1(i),dfs2(i);
      		}
      	}
      	build(1,1,n);
      	while(q--){
      		int u,v;
      		cin>>u>>v;
      		if(!D.check(u,v)){
      			cout<<"-1\n";
      		}
      		else{
      			int res=inf;
      			while(top[u]!=top[v]){
      				if(dep[top[u]]<dep[top[v]]){
      					swap(u,v);
      				}
      				res=min(res,query(1,1,n,dfn[top[u]],dfn[u]));
      				u=fa[top[u]];
      			}
      			if(dep[u]>dep[v]){
      				swap(u,v);
      			}
      			res=min(res,query(1,1,n,dfn[u]+1,dfn[v]));
      			cout<<res<<"\n";
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      E. [THUPC2022 初賽] 最小公倍樹

      考慮枚舉公因子 \(d\)\(d\)\([l,r]\) 之間的倍數(shù)形如 \(\{k\times d,(k+1)\times d,\dots,(k+p)\times d\}\),顯然所有點(diǎn)都向 \(k\times d\) 連邊是最優(yōu)的。于是邊數(shù)為 \(O((r-l)\log)\)。然后再跑 kruskal,時(shí)間復(fù)雜度為 \(O((r-l)\log^2)\)

      Code
      #include<bits/stdc++.h>
      #define int long long
      #define il inline
      #define pb push_back
      #define gcd __gcd
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e6+5;
      int n,m,fa[maxn],sz[maxn];
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      il void merge(int u,int v){
      	u=find(u),v=find(v);
      	if(u==v){
      		return ;
      	}
      	if(sz[u]>sz[v]){
      		sz[u]+=sz[v],fa[v]=u;
      	}
      	else{
      		sz[v]+=sz[u],fa[u]=v;
      	}
      }
      struct node{
      	int u,v,w;
      	il bool operator<(const node &x)const{
      		return w<x.w;
      	}
      };
      vector<node> e;
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      signed main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1;i<=m;i++){
      		for(int u=(n+i-1)/i*i,v=u+i;v<=m;v+=i){
      			e.pb((node){u,v,u/gcd(u,v)*v});
      		}
      	}
      	sort(e.begin(),e.end());
      	for(int i=n;i<=m;i++){
      		fa[i]=i,sz[i]=1;
      	}
      	int ans=0;
      	for(node i:e){
      		int u=i.u,v=i.v,w=i.w;
      		if(find(u)!=find(v)){
      			merge(u,v),ans+=w;
      		}
      	}
      	cout<<ans;
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      

      F. [BJWC2010] 嚴(yán)格次小生成樹

      首先建出最小生成樹。
      遍歷每一條非樹邊,考慮連上它后形成的環(huán),我們要從這個(gè)環(huán)上刪掉原有的最大的一條邊。當(dāng)然邊權(quán)和新邊不能相等。考慮新邊一定 \(\ge\) 原有的邊的最大值,因此用倍增維護(hù)路徑上的最大值和嚴(yán)格次大值即可。同時(shí),新加 \(2\) 條邊一定不如新加 \(1\) 條邊更優(yōu),所以依次枚舉非樹邊是正確的。時(shí)間復(fù)雜度 \(O(m\log m)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      #define pii pair<int,int>
      #define mp make_pair
      #define pb push_back
      #define fir first
      #define sec second
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+5,maxm=3e5+5;
      int n,m,dep[maxn],anc[maxn][22];
      struct node{
      	int mx1,mx2;
      	node(int mx1=-1,int mx2=-1):mx1(mx1),mx2(mx2){}
      	il node operator+(const node &x)const{
      		int hp[7];
      		hp[1]=mx1,hp[2]=mx2,hp[3]=x.mx1,hp[4]=x.mx2;
      		sort(hp+1,hp+5,greater<int>());
      		hp[unique(hp+1,hp+5)-hp]=-1;
      		return node(hp[1],hp[2]);
      	}
      }mxd[maxn][22];
      struct edge{
      	int u,v,w;
      	il bool operator<(const edge &x)const{
      		return w<x.w;
      	}
      }a[maxm];
      bool vis[maxm];
      vector<pii> e[maxn];
      il void dfs(int u){
      	dep[u]=dep[anc[u][0]]+1;
      	for(int i=1;i<=20;i++){
      		anc[u][i]=anc[anc[u][i-1]][i-1];
      		mxd[u][i]=mxd[u][i-1]+mxd[anc[u][i-1]][i-1];
      	}
      	for(pii i:e[u]){
      		int v=i.fir,w=i.sec;
      		if(v!=anc[u][0]){
      			anc[v][0]=u;
      			mxd[v][0].mx1=w;
      			dfs(v);
      		}
      	}
      }
      il node query(int u,int v){
      	if(dep[u]<dep[v]){
      		swap(u,v);
      	}
      	int ddep=dep[u]-dep[v],tmp=0;
      	node res;
      	while(ddep){
      		if(ddep&1){
      			res=res+mxd[u][tmp];
      			u=anc[u][tmp];
      		}
      		ddep>>=1,tmp++;
      	}
      	if(u==v){
      		return res;
      	}
      	for(int i=20;~i;i--){
      		if(anc[u][i]!=anc[v][i]){
      			res=res+mxd[u][i]+mxd[v][i];
      			u=anc[u][i],v=anc[v][i];
      		}
      	}
      	return res+mxd[u][0]+mxd[v][0];
      }
      struct{
      	int fa[maxn],sz[maxn];
      	il void init(){
      		for(int i=1;i<=n;i++){
      			fa[i]=i,sz[i]=1;
      		}
      	}
      	il int find(int x){
      		return x!=fa[x]?fa[x]=find(fa[x]):x;
      	}
      	il void merge(int u,int v){
      		u=find(u),v=find(v);
      		if(u==v){
      			return ;
      		}
      		if(sz[u]>sz[v]){
      			sz[u]+=sz[v],fa[v]=u;
      		}
      		else{
      			sz[v]+=sz[u],fa[u]=v;
      		}
      	}
      	il bool check(int u,int v){
      		return find(u)==find(v);
      	}
      }D;
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      //	cout<<cplx::usdmem()<<"\n";
      	cin>>n>>m;
      	for(int i=1;i<=m;i++){
      		cin>>a[i].u>>a[i].v>>a[i].w;
      	}
      	sort(a+1,a+m+1),D.init();
      	ll ans1=0,ans2=1e18;
      	for(int i=1,u,v,w;i<=m;i++){
      		u=a[i].u,v=a[i].v,w=a[i].w;
      		if(!D.check(u,v)){
      			D.merge(u,v);
      			vis[i]=1,ans1+=w;
      			e[u].pb(mp(v,w));
      			e[v].pb(mp(u,w));
      		}
      	}
      	dfs(1);
      	for(int i=1,u,v,w;i<=m;i++){
      		u=a[i].u,v=a[i].v,w=a[i].w;
      		if(vis[i]){
      			continue;
      		}
      		node tmp=query(u,v);
      		int hp[7];
      		hp[1]=tmp.mx1,hp[2]=tmp.mx2,hp[3]=w;
      		sort(hp+1,hp+4,greater<int>());
      		hp[unique(hp+1,hp+4)-hp]=-1;
      		if(~hp[2]){
      			ans2=min(ans2,ans1-hp[2]+hp[1]);
      		}
      	}
      	cout<<ans2;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      G. [APIO2013] 道路費(fèi)用

      \(k\le 20\),考慮 \(O(2^k)\) 暴力枚舉加入的邊。但是邊數(shù)很大,時(shí)間復(fù)雜度很高無法承受。
      考慮在一開始強(qiáng)制選這 \(k\) 條邊,然后跑最小生成樹,此時(shí)加入的邊就是一定會(huì)加入的邊。設(shè)這個(gè)邊集為 \(S\)
      \(S\) 連接的連通塊縮成點(diǎn),點(diǎn)數(shù)為 \(O(k)\)。再在原圖上對這些點(diǎn)跑最小生成樹,設(shè)加入的邊集為 \(T\),則 \(T\) 為加入那 \(k\) 條邊后有可能在最小生成樹中的邊。數(shù)量也為 \(O(k)\)
      然后暴力枚舉強(qiáng)制加入的邊,用 \(T\) 跑出最小生成樹,再用 \(T\) 中的非樹邊限制強(qiáng)制加入的邊即可。具體地,對于一條非樹邊 \((u,v)\),樹上 \(u\)\(v\) 的路徑中的所有邊都應(yīng)該 \(\ge\) 這條非樹邊的邊權(quán)。暴力跳父親即可。
      考慮統(tǒng)計(jì)答案,只需要計(jì)算通過每條邊的人數(shù),用 dfs 計(jì)算子樹權(quán)值和即可。
      時(shí)間復(fù)雜度 \(O(m\log m+2^kk^2)\)

      Code
      #include<bits/stdc++.h>
      #define int long long
      #define il inline
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      #define pb push_back
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=3e5+5;
      int n,m,k,a[maxn],bel[maxn];
      bool vis[maxn];
      vector<int> dk;
      vector<pii> e[maxn];
      struct edge{
      	int u,v,w;
      	il bool operator<(const edge &x)const{
      		return w<x.w;
      	}
      }em[maxn],ek[maxn];
      vector<edge> et;
      int fa[maxn],sz[maxn],ans;
      int mxe[maxn],dep[maxn],tof[maxn];
      il void init(){
      	for(int i=1;i<=n;i++){
      		fa[i]=i,sz[i]=1;
      	}
      }
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      il void merge(int u,int v){
      	u=find(u),v=find(v);
      	if(u==v){
      		return ;
      	}
      	if(sz[u]>sz[v]){
      		sz[u]+=sz[v],fa[v]=u;
      	}
      	else{
      		sz[v]+=sz[u],fa[u]=v;
      	}
      }
      il void dfs(int u){
      	dep[u]=dep[fa[u]]+1;
      	sz[u]=a[u];
      	for(pii i:e[u]){
      		int v=i.fir,w=i.sec;
      		if(v!=fa[u]){
      			fa[v]=u;
      			tof[v]=w;
      			dfs(v);
      			sz[u]+=sz[v];
      		}
      	}
      }
      il void solve(int S){
      	for(int u:dk){
      		fa[u]=u,sz[u]=1,e[u].clear();
      	}
      	for(int i=1,u,v;i<=k;i++){
      		if(S>>(i-1)&1){
      			u=bel[ek[i].u],v=bel[ek[i].v];
      			if(find(u)==find(v)){
      				return ;
      			}
      			merge(u,v);
      			e[u].pb(mp(v,-i));
      			e[v].pb(mp(u,-i));
      		}
      	}
      	for(int i=0;i<et.size();i++){
      		vis[i]=0;
      	}
      	for(int i=0,u,v,w;i<et.size();i++){
      		u=et[i].u,v=et[i].v,w=et[i].w;
      		if(find(u)!=find(v)){
      			merge(u,v);
      			vis[i]=1;
      			e[u].pb(mp(v,w));
      			e[v].pb(mp(u,w));
      		}
      	}
      	for(int i=1;i<=k;i++){
      		mxe[i]=INT_MAX;
      	}
      	for(int u:dk){
      		dep[u]=tof[u]=fa[u]=sz[u]=0;
      	}
      	dfs(bel[1]);
      //	puts("666");
      	for(int i=0,u,v,w;i<et.size();i++){
      //		cout<<i<<"\n";
      		if(vis[i]){
      			continue;
      		}
      		u=et[i].u,v=et[i].v,w=et[i].w;
      		if(dep[u]<dep[v]){
      			swap(u,v);
      		}
      //		cout<<dep[u]<<" "<<dep[v]<<"\n";
      		while(dep[u]>dep[v]){
      //			puts("666");
      			if(tof[u]<0){
      				mxe[-tof[u]]=min(mxe[-tof[u]],w);
      			}
      			u=fa[u];
      		}
      		while(u!=v){
      			if(tof[u]<0){
      				mxe[-tof[u]]=min(mxe[-tof[u]],w);
      			}
      			if(tof[v]<0){
      				mxe[-tof[v]]=min(mxe[-tof[v]],w);
      			}
      			u=fa[u],v=fa[v];
      		}
      	}
      	for(int u:dk){
      		if(tof[u]<0){
      			tof[u]=-mxe[-tof[u]];
      		}
      	}
      	int res=0;
      	for(int u:dk){
      		if(tof[u]<0){
      			res-=tof[u]*sz[u];
      		}
      	}
      	ans=max(ans,res);
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      signed main(){
      //	cout<<cplx::usdmem();
      	ios::sync_with_stdio(0),cin.tie(0);
      //	freopen("toll5.in","r",stdin);
      	cin>>n>>m>>k;
      //	cout<<n<<" "<<m<<" "<<k<<"\n";
      	for(int i=1;i<=m;i++){
      		cin>>em[i].u>>em[i].v>>em[i].w;
      	}
      	init(),sort(em+1,em+m+1);
      	for(int i=1;i<=k;i++){
      		cin>>ek[i].u>>ek[i].v;
      		merge(ek[i].u,ek[i].v);
      	}
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      	}
      	for(int i=1,u,v;i<=m;i++){
      		u=em[i].u,v=em[i].v;
      		if(find(u)!=find(v)){
      			merge(u,v);
      			vis[i]=1;
      		}
      	}
      	init();
      	for(int i=1,u,v;i<=m;i++){
      		if(vis[i]){
      			u=find(em[i].u);
      			v=find(em[i].v);
      			if(sz[u]>sz[v]){
      				sz[u]+=sz[v];
      				a[u]+=a[v];
      				fa[v]=u;
      			}
      			else{
      				sz[v]+=sz[u];
      				a[v]+=a[u];
      				fa[u]=v;
      			}
      		}
      	}
      	for(int i=1;i<=n;i++){
      		bel[i]=find(i);
      		if(bel[i]==i){
      			dk.pb(i);
      		}
      	}
      	init();
      	for(int i=1,u,v,w;i<=m;i++){
      		u=bel[em[i].u],v=bel[em[i].v],w=em[i].w;
      		if(find(u)!=find(v)){
      			et.pb((edge){u,v,w});
      			merge(u,v);
      		}
      	}
      	for(int S=0;S<1<<k;S++){
      //		cout<<bitset<15>(S)<<"\n";
      		solve(S);
      	}
      	cout<<ans;
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      /*
      100000 299989 12
      */
      

      H. [藍(lán)橋杯 2015 省 A] 災(zāi)后重建

      建 kruskal 重構(gòu)樹,問題轉(zhuǎn)化為求 \(\operatorname{lca}\)
      根號分治,對于 \(k>\sqrt{n}\) 暴力求,剩下的對于剩余系去建線段樹區(qū)間查詢。時(shí)間復(fù)雜度 \(O(q\sqrt{n})\)
      然而空間十分爆炸。原因是對于每個(gè)剩余系都建線段樹是無法接受的。因此將查詢離線下來,就可以只建一棵線段樹,不斷重構(gòu)即可。然而原題數(shù)據(jù)沒有卡這一點(diǎn)。
      空間不正確的代碼:

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      #define lwrb lower_bound
      #define uprb upper_bound
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5,maxb=250;
      int n,m,q,blen,fa[maxn],zhi[maxn];
      vector<int> e[maxn];
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      struct edge{
      	int u,v,w;
      	il bool operator<(const edge &x)const{
      		return w<x.w;
      	}
      }a[maxn];
      int dfn[maxn],oula[maxn],idx[maxn],cnt;
      il void dfs(int u){
      	dfn[u]=++cnt;
      	oula[cnt]=cnt;
      	idx[cnt]=u;
      	for(int v:e[u]){
      		if(v!=fa[u]){
      			dfs(v);
      			oula[++cnt]=dfn[u];
      		}
      	}
      }
      struct{
      	int Log[maxn],st[maxn][22];
      	il void init(){
      		for(int i=2;i<=cnt;i++){
      			Log[i]=Log[i>>1]+1;
      		}
      		for(int i=1;i<=cnt;i++){
      			st[i][0]=oula[i];
      		}
      		for(int j=1;j<=Log[cnt];j++){
      			for(int i=1;i+(1<<j)-1<=cnt;i++){
      				st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
      			}
      		}
      	}
      	il int query(int l,int r){
      		int tmp=Log[r-l+1];
      		return min(st[l][tmp],st[r-(1<<tmp)+1][tmp]);
      	}
      }ST;
      il int lca(int u,int v){
      	if(dfn[u]>dfn[v]){
      		swap(u,v);
      	}
      	return idx[ST.query(dfn[u],dfn[v])];
      }
      vector<int> syx[maxb][maxb];
      struct stree{
      	#define lid id<<1
      	#define rid id<<1|1
      	int num;
      	vector<int> tr;
      	il void pushup(int id){
      		tr[id]=lca(tr[lid],tr[rid]);
      	}
      	il void build(int id,int l,int r,int x,int y){
      		if(l>r){
      			return ;
      		}
      		if(l==r){
      			tr[id]=syx[x][y][l];
      			return ;
      		}
      		int mid=(l+r)>>1;
      		build(lid,l,mid,x,y);
      		build(rid,mid+1,r,x,y);
      		pushup(id);
      	}
      	stree(int x=0,int y=0):num(syx[x][y].size()),tr(num<<2,0){
      //		puts("666");
      		build(1,0,num-1,x,y);
      	}
      	il int query(int id,int L,int R,int l,int r){
      		if(L>=l&&R<=r){
      			return tr[id];
      		}
      		int mid=(L+R)>>1;
      		if(r<=mid){
      			return query(lid,L,mid,l,r);
      		}
      		if(l>mid){
      			return query(rid,mid+1,R,l,r);
      		}
      		return lca(query(lid,L,mid,l,r),query(rid,mid+1,R,l,r));
      	}
      	il int query(int id,int l,int r){
      		return query(1,0,num-1,l,r);
      	}
      	#undef lid
      	#undef rid
      }SG[maxb][maxb];
      bool vis[maxb][maxb];
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      //	freopen("H.in","r",stdin);
      //	freopen("H.out","w",stdout);
      //	cout<<cplx::usdmem();
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>q;
      	for(int i=1;i<=m;i++){
      		cin>>a[i].u>>a[i].v>>a[i].w;
      	}
      	sort(a+1,a+m+1);
      	int tot=n;
      	for(int i=1;i<=n<<1;i++){
      		fa[i]=i;
      	}
      	for(int i=1,u,v,w;i<=m;i++){
      //	puts("666");
      		u=a[i].u,v=a[i].v,w=a[i].w;
      		u=find(u),v=find(v);
      		if(u!=v){
      			fa[u]=fa[v]=++tot;
      			zhi[tot]=w;
      			e[tot].pb(u),e[tot].pb(v);
      		}
      	}
      	dfs(tot),ST.init();
      	blen=sqrt(n);
      //	cout<<blen<<"\n";
      //	bool begin;
      //	int num=0;
      	for(int i=1;i<=blen;i++){
      		for(int j=1;j<=n;j++){
      			syx[i][j%i].pb(j);
      //			num++;
      		}
      	}
      //	cout<<num<<"\n";
      //	bool end;
      //	cout<<(&end-&begin)/1048576.0<<"\n";
      	while(q--){
      		int l,r,k,c;
      		cin>>l>>r>>k>>c;
      		if(k>blen){
      			int tmp=l;
      			if(l%k<c){
      				tmp+=c-l%k;
      			}
      			else if(l%k>c){
      				tmp-=l%k-c;
      				tmp+=k;
      			}
      			for(int i=tmp+k;i<=r;i+=k){
      				tmp=lca(tmp,i);
      			}
      			cout<<zhi[tmp]<<"\n";
      			continue;
      		}
      		if(!vis[k][c]){
      			SG[k][c]=stree(k,c);
      			vis[k][c]=1;
      		}
      		cout<<zhi[SG[k][c].query(1,lwrb(syx[k][c].begin(),syx[k][c].end(),l)-syx[k][c].begin(),uprb(syx[k][c].begin(),syx[k][c].end(),r)-syx[k][c].begin()-1)]<<"\n";
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      離線卡空間的代碼:

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      #define lwrb lower_bound
      #define uprb upper_bound
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5,maxb=250;
      int n,m,q,blen,fa[maxn],zhi[maxn];
      vector<int> e[maxn];
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      struct edge{
      	int u,v,w;
      	il bool operator<(const edge &x)const{
      		return w<x.w;
      	}
      }a[maxn];
      int dfn[maxn],oula[maxn],idx[maxn],cnt;
      il void dfs(int u){
      	dfn[u]=++cnt;
      	oula[cnt]=cnt;
      	idx[cnt]=u;
      	for(int v:e[u]){
      		if(v!=fa[u]){
      			dfs(v);
      			oula[++cnt]=dfn[u];
      		}
      	}
      }
      struct{
      	int Log[maxn],st[maxn][22];
      	il void init(){
      		for(int i=2;i<=cnt;i++){
      			Log[i]=Log[i>>1]+1;
      		}
      		for(int i=1;i<=cnt;i++){
      			st[i][0]=oula[i];
      		}
      		for(int j=1;j<=Log[cnt];j++){
      			for(int i=1;i+(1<<j)-1<=cnt;i++){
      				st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
      			}
      		}
      	}
      	il int query(int l,int r){
      		int tmp=Log[r-l+1];
      		return min(st[l][tmp],st[r-(1<<tmp)+1][tmp]);
      	}
      }ST;
      il int lca(int u,int v){
      	if(dfn[u]>dfn[v]){
      		swap(u,v);
      	}
      	return idx[ST.query(dfn[u],dfn[v])];
      }
      vector<int> syx[maxb][maxb];
      struct stree{
      	#define lid id<<1
      	#define rid id<<1|1
      	int num,tr[maxn<<2];
      	il void pushup(int id){
      		tr[id]=lca(tr[lid],tr[rid]);
      	}
      	il void build(int id,int l,int r,int x,int y){
      		if(l>r){
      			return ;
      		}
      		if(l==r){
      			tr[id]=syx[x][y][l];
      			return ;
      		}
      		int mid=(l+r)>>1;
      		build(lid,l,mid,x,y);
      		build(rid,mid+1,r,x,y);
      		pushup(id);
      	}
      	stree(int x=0,int y=0):num(syx[x][y].size()){
      //		puts("666");
      		build(1,0,num-1,x,y);
      	}
      	il int query(int id,int L,int R,int l,int r){
      		if(L>=l&&R<=r){
      			return tr[id];
      		}
      		int mid=(L+R)>>1;
      		if(r<=mid){
      			return query(lid,L,mid,l,r);
      		}
      		if(l>mid){
      			return query(rid,mid+1,R,l,r);
      		}
      		return lca(query(lid,L,mid,l,r),query(rid,mid+1,R,l,r));
      	}
      	il int query(int id,int l,int r){
      		return query(1,0,num-1,l,r);
      	}
      	#undef lid
      	#undef rid
      }SG;
      struct node{
      	int l,r,k,c,id;
      	il bool operator<(const node &x)const{
      		return k<x.k||k==x.k&&c<x.c;
      	}
      }wt[maxn];
      int ans[maxn];
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      //	freopen("H.in","r",stdin);
      //	freopen("H.out","w",stdout);
      //	cout<<cplx::usdmem();
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>q;
      	for(int i=1;i<=m;i++){
      		cin>>a[i].u>>a[i].v>>a[i].w;
      	}
      	sort(a+1,a+m+1);
      	int tot=n;
      	for(int i=1;i<=n<<1;i++){
      		fa[i]=i;
      	}
      	for(int i=1,u,v,w;i<=m;i++){
      //	puts("666");
      		u=a[i].u,v=a[i].v,w=a[i].w;
      		u=find(u),v=find(v);
      		if(u!=v){
      			fa[u]=fa[v]=++tot;
      			zhi[tot]=w;
      			e[tot].pb(u),e[tot].pb(v);
      		}
      	}
      	dfs(tot),ST.init();
      	blen=sqrt(n);
      //	cout<<blen<<"\n";
      //	bool begin;
      //	int num=0;
      	for(int i=1;i<=blen;i++){
      		for(int j=1;j<=n;j++){
      			syx[i][j%i].pb(j);
      //			num++;
      		}
      	}
      //	cout<<num<<"\n";
      //	bool end;
      //	cout<<(&end-&begin)/1048576.0<<"\n";
      	for(int i=1;i<=q;i++){
      		cin>>wt[i].l>>wt[i].r>>wt[i].k>>wt[i].c;
      		wt[i].id=i;
      	}
      	sort(wt+1,wt+q+1);
      	for(int i=1;i<=q;i++){
      		int l=wt[i].l,r=wt[i].r,k=wt[i].k,c=wt[i].c;
      		if(k>blen){
      			int tmp=l;
      			if(l%k<c){
      				tmp+=c-l%k;
      			}
      			else if(l%k>c){
      				tmp-=l%k-c;
      				tmp+=k;
      			}
      			for(int i=tmp+k;i<=r;i+=k){
      				tmp=lca(tmp,i);
      			}
      			ans[wt[i].id]=zhi[tmp];
      			continue;
      		}
      		if(k!=wt[i-1].k||c!=wt[i-1].c){
      			SG=stree(k,c);
      		}
      		ans[wt[i].id]=zhi[SG.query(1,lwrb(syx[k][c].begin(),syx[k][c].end(),l)-syx[k][c].begin(),uprb(syx[k][c].begin(),syx[k][c].end(),r)-syx[k][c].begin()-1)];
      	}
      	for(int i=1;i<=q;i++){
      		cout<<ans[i]<<"\n";
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      I. Mathematics Curriculum

      子段最大值個(gè)數(shù)即為這個(gè)點(diǎn)在大根笛卡爾樹中的深度。考慮建樹過程即可證明。
      設(shè) \(f_{i,j,k}\) 表示 \(i\) 個(gè)點(diǎn)的笛卡爾樹,其中 \(i\) 是最大的點(diǎn),第 \(k\) 層有 \(j\) 個(gè)點(diǎn)。枚舉左右子樹即可得到方程:

      \[f_{i,j,k}=\sum_{x=0}^{i-1}\sum_{y=0}^{j}{i-1\choose{x}}\times f_{x,y,k-1}\times f_{i-x-1,j-y,k-1} \]

      邊界條件 \(f_{i,1,1}=i!\)。轉(zhuǎn)移是 \(O(n^5)\) 的,考慮優(yōu)化。

      • 對于 \(k>i\),只有 \(f_{i,0,k}=i!\),其它值都為 \(0\)
      • 三個(gè)乘數(shù)都不為 \(0\) 時(shí)轉(zhuǎn)移才有效。

      于是就可以通過。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=105;
      int n,m,num,mod;
      int fac[maxn],C[maxn][maxn];
      int f[maxn][maxn][maxn];
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      //	freopen("I.in","r",stdin);
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>num>>mod;
      	fac[0]=C[0][0]=1;
      	for(int i=1;i<=n;i++){
      		fac[i]=fac[i-1]*1ll*i%mod;
      		C[i][0]=1;
      		for(int j=1;j<=i;j++){
      			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
      		}
      	}
      	for(int i=0;i<=m;i++){
      		f[0][0][i]=1;
      	}
      	f[1][0][0]=f[1][1][1]=1;
      	for(int i=2;i<=m;i++){
      		f[1][0][i]=1;
      	}
      	for(int i=2;i<=n;i++){
      		f[i][1][1]=fac[i];
      		for(int k=2;k<=m;k++){
      			if(k>i){
      				f[i][0][k]=fac[i];
      				continue;
      			}
      			for(int j=0;j<=i;j++){
      				for(int x=0;x<i;x++){
      					if(!C[i-1][x]){
      						continue;
      					}
      					for(int y=0;y<=j;y++){
      						if(f[x][y][k-1]&&f[i-1-x][j-y][k-1]){
      							(f[i][j][k]+=C[i-1][x]*1ll*f[x][y][k-1]%mod*f[i-1-x][j-y][k-1]%mod)%=mod;
      						}
      					}
      				}
      			}
      		}
      	}
      	cout<<f[n][num][m];
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      J. 「OICon-02」maxiMINImax

      用單調(diào)棧可以求出以 \(a_i\) 為最小值和最大值的區(qū)間個(gè)數(shù) \(qmn_i\)\(qmx_i\)
      從小到大枚舉第二個(gè)區(qū)間的最小值,記 \(p_i\) 表示 \(i\) 的位置,則對于 \(i\) 的答案即為:

      \[\sum_{j=1}^{p_i-1}\sum_{k=p_i+1}^{n}{qmn_{p_i}qmx_jqmx_k(i-a_j)(i-a_k)} \]

      簡單推式子后得到:
      \( qmn_{p_i}(\sum{qmx_j}\sum{qmx_k}i^2-\sum{qmx_ja_j}\sum{qmx_k}i-\sum{qmx_j}\sum{qmx_ka_k}i+\sum{qmx_ja_j}\sum{qmx_ka_k}) \)
      于是開兩棵樹狀數(shù)組維護(hù) \(qmx_j\)\(qmx_ja_j\) 就好了。時(shí)間復(fù)雜度 \(O(n\log n)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e6+5,mod=9712176;
      int n,a[maxn],p[maxn],zhan[maxn];
      int lmn[maxn],rmn[maxn];
      int lmx[maxn],rmx[maxn];
      int qmn[maxn],qmx[maxn];
      struct{
      	int tr[maxn];
      	il int lowbit(int x){
      		return x&-x;
      	}
      	il void upd(int p,int v){
      		for(;p<=n;p+=lowbit(p)){
      			(tr[p]+=v)%=mod;
      		}
      	}
      	il int query(int p){
      		int res=0;
      		for(;p;p-=lowbit(p)){
      			(res+=tr[p])%=mod;
      		}
      		return res;
      	}
      	il int query(int l,int r){
      		return (query(r)-query(l-1)+mod)%mod;
      	}
      }F1,F2;
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n;
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      		p[a[i]]=i;
      	}
      	for(int i=1,top=0;i<=n;i++){
      		while(top&&a[zhan[top]]>a[i]){
      			top--;
      		}
      		lmn[i]=zhan[top];
      		zhan[++top]=i;
      	}
      	for(int i=1,top=0;i<=n;i++){
      		while(top&&a[zhan[top]]<a[i]){
      			top--;
      		}
      		lmx[i]=zhan[top];
      		zhan[++top]=i;
      	}
      	zhan[0]=n+1;
      	for(int i=n,top=0;i;i--){
      		while(top&&a[zhan[top]]>a[i]){
      			top--;
      		}
      		rmn[i]=zhan[top];
      		zhan[++top]=i;
      	}
      	for(int i=n,top=0;i;i--){
      		while(top&&a[zhan[top]]<a[i]){
      			top--;
      		}
      		rmx[i]=zhan[top];
      		zhan[++top]=i;
      	}
      	for(int i=1;i<=n;i++){
      		qmn[i]=(i-lmn[i])*1ll*(rmn[i]-i)%mod;
      		qmx[i]=(i-lmx[i])*1ll*(rmx[i]-i)%mod;
      	}
      	int ans=0;
      	for(int i=1,xj,xaj,xk,xak;i<=n;i++){
      		xj=F1.query(1,p[i]-1);
      		xaj=F2.query(1,p[i]-1);
      		xk=F1.query(p[i]+1,n);
      		xak=F2.query(p[i]+1,n);
      		(ans+=qmn[p[i]]*1ll*(xj*1ll*xk%mod*i%mod*i%mod-xaj*1ll*xk%mod*i%mod-xj*1ll*xak%mod*i%mod+xaj*1ll*xak%mod)%mod)%=mod;
      		(ans+=mod)%=mod;
      		F1.upd(p[i],qmx[p[i]]);
      		F2.upd(p[i],qmx[p[i]]*1ll*i%mod);
      	}
      	cout<<ans;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      
      posted @ 2025-02-04 08:21  zhangxy__hp  閱讀(65)  評論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产18禁一区二区三区| 中国CHINA体内裑精亚洲日本| 9久9久热精品视频在线观看 | 成人午夜福利视频一区二区| 午夜男女爽爽影院免费视频下载| 平阳县| 伦伦影院午夜理论片| 亚洲更新最快无码视频| 亚洲an日韩专区在线| 欧美成人精品手机在线| 国产色无码精品视频免费| 欧美亚洲另类自拍偷在线拍| 欧美亚洲另类制服卡通动漫| 无码人妻久久一区二区三区app| 亚洲中文字幕国产综合| 97午夜理论电影影院| AV免费网址在线观看| 亚洲欧洲日韩精品在线| 亚洲AV无码一二区三区在线播放| 欧美成人va免费大片视频| av深夜免费在线观看| 卢湾区| 白嫩人妻精品一二三四区| 久久精品a亚洲国产v高清不卡| 日本一道一区二区视频| 久久热精品视频在线视频| 亚洲综合无码一区二区三区不卡| 成A人片亚洲日本久久| 人妻系列无码专区无码中出| 亚洲欧洲av一区二区久久| 久久亚洲日韩精品一区二区三区 | 日本韩无专砖码高清观看| 国产盗摄xxxx视频xxxx| www插插插无码免费视频网站| 日韩在线视频线观看一区| 久久亚洲精品成人av无| 喷潮出白浆视频在线观看| 亚洲欧美日本久久网站| 亚洲精品美女一区二区| 丰满岳乱妇一区二区三区| 午夜好爽好舒服免费视频|