P4764-[CERC2014]Pork barrel【主席树,LCT,最小生成树】
生活随笔
收集整理的這篇文章主要介紹了
P4764-[CERC2014]Pork barrel【主席树,LCT,最小生成树】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.org/problem/P4764
題目大意
給出一張圖,若干個詢問,每個詢問求只使用權值在[L,R][L,R][L,R]這個范圍內的邊組成的最小生成樹權值和,強制在線。
解題思路
我們先考慮LLL固定,這時我們發現我們可以從LLL開始往右做最小生成樹,若一條邊可以產生貢獻值就為該邊權值,否則權值為0,然后我們在線段樹上修改查詢即可。
但是現在LLL端點固定,我們考慮從大到小加邊,我們加入一條更小的邊(x,y,w)(x,y,w)(x,y,w),若x,yx,yx,y不聯通就直接加入,若聯通就選取x,yx,yx,y路徑上權值最大的一條邊刪去即可,這個我們用LCTLCTLCT可以O(log?n)O(\log n)O(logn)維護。
然后因為強制在線所以我們可以用主席樹儲存答案。
LCTLCTLCT維護最小生成樹,我們可以將一條邊拆成兩個點和一條邊,然后路徑查詢即可。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> using namespace std; const int N=200010,M=3600010; int T,n,m,q,ans,from[N],sum[N],val[N],fa[N],root[N]; struct Line_Cut_Tree{#define ls son[x][0]#define rs son[x][1]int son[N][2],fa[N];bool r[N];stack<int> s;bool Nroot(int x){return fa[x]&&(son[fa[x]][0]==x||son[fa[x]][1]==x);}void PushUp(int x){sum[x]=val[x];from[x]=x;if(son[x][0]&&sum[ls]>sum[x]) sum[x]=sum[ls],from[x]=from[ls];if(son[x][1]&&sum[rs]>sum[x]) sum[x]=sum[rs],from[x]=from[rs];return;}void PushR(int x){swap(ls,rs);r[x]^=1;return;}void PushDown(int x){if(r[x])PushR(ls),PushR(rs),r[x]^=1;return;}void Rotate(int x){int y=fa[x],z=fa[y],k=(son[y][1]==x),w=son[x][!k];if(Nroot(y)) son[z][son[z][1]==y]=x;son[x][!k]=y;son[y][k]=w;if(w) fa[w]=y;fa[y]=x;fa[x]=z;PushUp(y);return;}void Splay(int x){int y=x,z=0;s.push(x);while(Nroot(s.top())) s.push(fa[s.top()]);while(!s.empty()) PushDown(s.top()),s.pop();while(Nroot(x)){y=fa[x];z=fa[y];if(Nroot(y))Rotate((son[y][0]==x)^(son[z][0]==y)?x:y);Rotate(x);}PushUp(x);return;}void Access(int x){for(int y=0;x;x=fa[y=x])Splay(x),rs=y,PushUp(x);return;}void MakeRoot(int x){Access(x);Splay(x);PushR(x);return;}int Split(int x,int y){MakeRoot(x);Access(y);Splay(y);return from[y];}void Link(int x,int y){MakeRoot(x);fa[x]=y;Access(x);return;}void Cut(int x,int y){MakeRoot(x);Access(y);Splay(y);fa[son[y][0]]=0;son[y][0]=0;PushUp(y);return;}void Clean(){memset(son,0,sizeof(son));memset(fa,0,sizeof(fa));memset(r,0,sizeof(r));}#undef ls#undef rs }LCT; struct Keep_Seq_Tree{int w[M],lson[M],rson[M],cnt;int Insert(int y,int L,int R,int pos,int val){int x=++cnt;w[x]=w[y]+val;lson[x]=lson[y];rson[x]=rson[y];if(L==R) return x;int mid=(L+R)>>1;if(pos<=mid) lson[x]=Insert(lson[y],L,mid,pos,val);else rson[x]=Insert(rson[y],mid+1,R,pos,val);return x;}int Query(int x,int L,int R,int l,int r){if(!x) return 0;if(L>R) return 0;if(L==l&&R==r) return w[x];int mid=(L+R)>>1;if(r<=mid) return Query(lson[x],L,mid,l,r);if(l>mid) return Query(rson[x],mid+1,R,l,r);return Query(lson[x],L,mid,l,mid)+Query(rson[x],mid+1,R,mid+1,r);} }Tree; struct Enode{int x,y,w; }a[N]; int Find(int x) {return fa[x]==x?x:fa[x]=Find(fa[x]);} bool cmp(Enode x,Enode y) {return x.w>y.w;} int get_idx(int x) {int l=1,r=m;while(l<=r){int mid=(l+r)>>1;if(a[mid].w>=x) l=mid+1;else r=mid-1;}return min(r,m); } int get_idy(int x) {int l=1,r=m;while(l<=r){int mid=(l+r)>>1;if(a[mid].w>x) l=mid+1;else r=mid-1;}return min(l,m); } int main() {scanf("%d",&T);while(T--){LCT.Clean();Tree.cnt=0;ans=0;memset(val,0,sizeof(val));memset(sum,0,sizeof(sum));memset(from,0,sizeof(from));scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);sort(a+1,a+1+m,cmp);for(int i=1;i<=m;i++)val[i+n]=sum[i+n]=a[i].w,from[i+n]=i+n;for(int i=1;i<=m;i++){root[i]=root[i-1];if(Find(a[i].x)==Find(a[i].y)){int p=LCT.Split(a[i].x,a[i].y);LCT.Cut(p,a[p-n].x);LCT.Cut(p,a[p-n].y);root[i]=Tree.Insert(root[i],1,m,p-n,-a[p-n].w);}else fa[fa[a[i].x]]=fa[a[i].y];LCT.Link(a[i].x,i+n);LCT.Link(a[i].y,i+n);root[i]=Tree.Insert(root[i],1,m,i,a[i].w);}scanf("%d",&q);while(q--){int x,y,idx,idy;scanf("%d%d",&x,&y);x-=ans;y-=ans;idx=get_idx(x);idy=get_idy(y);ans=Tree.Query(root[idx],1,m,idy,m);printf("%d\n",ans);}} }總結
以上是生活随笔為你收集整理的P4764-[CERC2014]Pork barrel【主席树,LCT,最小生成树】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果手机铃声怎么设置苹果电脑如何设置铃声
- 下一篇: jzoj2908,P1527-[集训队互