日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ4860 Beijing2017树的难题(点分治+单调队列)

發(fā)布時間:2023/12/20 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ4860 Beijing2017树的难题(点分治+单调队列) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  考慮點分治。對子樹按照根部顏色排序,每次處理一種顏色的子樹,對同色和不同色兩種情況分別做一遍即可,單調(diào)隊列優(yōu)化。但是注意到這里每次使用單調(diào)隊列的復(fù)雜度是O(之前的子樹最大深度+該子樹深度),一不小心就退化成O(n2)。于是我們按照同顏色最大深度為第一關(guān)鍵字、子樹深度為第二關(guān)鍵字排序,每次處理完一種顏色再與之前的其他顏色合并,這樣每次的復(fù)雜度就是其自身深度了。

#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<cassert> using namespace std; #define ll long long #define N 200010 #define inf 2100000000 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() {int x=0,f=1;char c=getchar();while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f; } int n,m,l,r,p[N],a[N],mxdeep[N],colordeep[N],deep[N],size[N],len[N],f[N],g[N],q[N][2],Q[N],t,ans=-inf; bool flag[N]; struct data{int to,nxt,color; }edge[N<<1]; struct data2 {int x,y;bool operator <(const data2&a) const{return colordeep[y]<colordeep[a.y]||colordeep[y]==colordeep[a.y]&&y<a.y||colordeep[y]==colordeep[a.y]&&y==a.y&&mxdeep[x]<mxdeep[a.x];} }v[N]; void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].color=z,p[x]=t;} void make(int k,int from) {size[k]=1;for (int i=p[k];i;i=edge[i].nxt)if (edge[i].to!=from&&!flag[edge[i].to]){deep[edge[i].to]=deep[k]+1;make(edge[i].to,k);size[k]+=size[edge[i].to];} } int findroot(int k,int s) {int mx=0;for (int i=p[k];i;i=edge[i].nxt) if (size[edge[i].to]<size[k]&&size[edge[i].to]>size[mx]&&!flag[edge[i].to]) mx=edge[i].to;if ((size[mx]<<1)>s) return findroot(mx,s);else return k; } void findmx(int k,int from,int root) {mxdeep[root]=max(mxdeep[root],deep[k]);for (int i=p[k];i;i=edge[i].nxt)if (edge[i].to!=from&&!flag[edge[i].to]) findmx(edge[i].to,k,root); } inline void ins(int k,int &head,int &tail,int *f){while (head<=tail&&f[Q[tail]]<f[k]) tail--;Q[++tail]=k;} inline void pop(int k,int &head,int &tail){while (head<=tail&&Q[head]>k) head++;} void bfs(int k,int last,int v,int d) {int head=0,tail=1;q[1][0]=k,q[1][1]=last;int h=1,t=0;for (int i=min(d,r);i>=l;i--) ins(i,h,t,g);do{int x=q[++head][0];if (deep[x]>=l&&deep[x]<=r) ans=max(ans,len[x]);if (deep[x]>deep[q[head-1][0]]){pop(r-deep[x],h,t);if (l-deep[x]>=0&&l-deep[x]<=d) ins(l-deep[x],h,t,g);}if (h<=t) ans=max(ans,len[x]+g[Q[h]]+v);for (int i=p[x];i;i=edge[i].nxt)if (deep[edge[i].to]>deep[x]&&!flag[edge[i].to]){len[edge[i].to]=len[x];if (edge[i].color!=q[head][1]) len[edge[i].to]+=a[edge[i].color];q[++tail][0]=edge[i].to,q[tail][1]=edge[i].color;}}while (head<tail); } void update(int k,int from) {g[deep[k]]=max(g[deep[k]],len[k]);for (int i=p[k];i;i=edge[i].nxt)if (edge[i].to!=from&&!flag[edge[i].to]) update(edge[i].to,k); } void solve(int k) {make(k,k);k=findroot(k,size[k]);flag[k]=1;deep[k]=0;make(k,k);int cnt=0;for (int i=p[k];i;i=edge[i].nxt)if (!flag[edge[i].to]){colordeep[edge[i].color]=mxdeep[edge[i].to]=0,findmx(edge[i].to,edge[i].to,edge[i].to);cnt++,v[cnt].x=edge[i].to,v[cnt].y=edge[i].color;}for (int i=p[k];i;i=edge[i].nxt)if (!flag[edge[i].to]) colordeep[edge[i].color]=max(colordeep[edge[i].color],mxdeep[edge[i].to]);sort(v+1,v+cnt+1);for (int i=1;i<=cnt;i++){int t=i-1,d=0;while (t<cnt&&v[t+1].y==v[i].y){len[v[++t].x]=a[v[i].y];bfs(v[t].x,v[t].y,-a[v[i].y],d);update(v[t].x,v[t].x);d=mxdeep[v[t].x];}int H=1,T=0;for (int j=min(colordeep[v[i-1].y],r);j>=l;j--) ins(j,H,T,f);for (int j=1;j<=d;j++){pop(r-j,H,T);if (l>=j&&l-j<=d) ins(l-j,H,T,f);if (H<=T) ans=max(ans,g[j]+f[Q[H]]);}for (int j=0;j<=d;j++) f[j]=max(f[j],g[j]),g[j]=-inf;i=t;}for (int i=0;i<=mxdeep[v[cnt].x];i++) f[i]=-inf;for (int i=p[k];i;i=edge[i].nxt)if (!flag[edge[i].to]) solve(edge[i].to); } int main() { #ifndef ONLINE_JUDGEfreopen("bzoj4860.in","r",stdin);freopen("bzoj4860.out","w",stdout);const char LL[]="%I64d\n"; #elseconst char LL[]="%lld\n"; #endifn=read(),m=read(),l=read(),r=read();for (int i=0;i<=n;i++) f[i]=g[i]=-inf;for (int i=1;i<=m;i++) a[i]=read();for (int i=1;i<n;i++){int x=read(),y=read(),z=read();addedge(x,y,z),addedge(y,x,z);}solve(1);cout<<ans;return 0; }

?

轉(zhuǎn)載于:https://www.cnblogs.com/Gloid/p/10004006.html

總結(jié)

以上是生活随笔為你收集整理的BZOJ4860 Beijing2017树的难题(点分治+单调队列)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。