【JZOJ5433】图
来源:互联网 发布:java从入门到精通 编辑:程序博客网 时间:2024/06/08 04:39
Description
有一个n个点A+B条边的无向连通图,有一变量x,每条边的权值都是一个关于x的简单多项式,其中有A条边的权值是k+x,另外B条边的权值是k-x,如果只保留权值形如k+x的边,那么这个图仍是一个连通图,如果只保留权值形如k-x的边,这个图也依然是一个连通图。
给出q组询问,每组询问给出x的值,问此时这个无向连通图的最小生成树权值是多少。
Solution
有一个肯(xian)定(ran)的结论:无论 x 的值是多少,最后的最小生成树的边一定是k+x边构成的图中的最小生成树上的边或k-x边构成的图中的最小生成树上的边。
于是,先把k+x图建出来最小生成树,将k-x中最小生成树的边拿出来排序,从小到大加进k+x图,每次把形成新环上最大的k+x边删掉,同时算出这条k-x边替代环上最大k+x边的下界,然后把这些下界排序,同时把询问挂上去查询即可。
这里可能加入的两条k-x边之间有交,但实际上没有关系,k小的那条边会先做出贡献。
删边加边可以用LCT维护。
Code
#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)#define N 100010#define ll long long#define inf 2147483647using namespace std;struct node{ int u,v; ll w;}a[N*2],b[N*2];int fa[N*5],son[N*5][2],mx[N*5],p[N*5],sz[N*5],rev[N*5];ll va[N*5];int pd(int x){ return x==son[fa[x]][1];}void update(int x){ int l=son[x][0],r=son[x][1]; mx[x]=x; if(va[mx[l]]>va[mx[x]]) mx[x]=mx[l]; if(va[mx[r]]>va[mx[x]]) mx[x]=mx[r]; sz[x]=1+sz[l]+sz[r];}void put(int x){ if(!rev[x]) return; swap(son[x][0],son[x][1]); rev[son[x][0]]^=1,rev[son[x][1]]^=1; rev[x]=0;}int d[N];void down(int x,int y){ d[0]=0; while(x!=y) d[++d[0]]=x,x=fa[x]; fd(i,d[0],1) put(d[i]);}void rotate(int x){ int y=fa[x],t=pd(x); son[y][t]=son[x][1-t]; if(son[x][1-t]) fa[son[x][1-t]]=y; fa[x]=fa[y]; if(fa[y]) son[fa[y]][pd(y)]=x; else p[x]=p[y],p[y]=0; son[x][1-t]=y,fa[y]=x; update(y),update(x);}void splay(int x,int t){ down(x,t); while(fa[x]!=t) { int y=fa[x]; if(fa[y]!=t) if(pd(y)==pd(x)) rotate(y); else rotate(x); rotate(x); }}void access(int x){ int y=0; while(x) { splay(x,0); fa[son[x][1]]=0,p[son[x][1]]=x; son[x][1]=y,fa[y]=x,p[y]=0; update(x),y=x,x=p[x]; }}void makeroot(int x){ access(x),splay(x,0),rev[x]^=1;}void link(int x,int y){ makeroot(x),p[x]=y;}void cut(int x,int y){ makeroot(x),access(y); splay(y,0),son[y][0]=fa[x]=p[x]=0; update(y);}bool check(int x,int y){ makeroot(x),access(y); splay(x,0); while(y && y!=x) y=fa[y]; if(!y) return false; return true;}int query(int x,int y){ makeroot(x),access(y),splay(x,0); return mx[x];}int fat[N];int getfa(int x){ return fat[x]==x?fat[x]:fat[x]=getfa(fat[x]);}struct node2{ int x,t;}Q[N];bool cmp(node x,node y){ return x.w<y.w;}bool cmp2(node2 x,node2 y){ return x.x<y.x;}int z[N];ll an[N];int tot=0;int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); int n,A,B,q; scanf("%d %d %d %d",&n,&A,&B,&q); fo(i,0,n) va[i]=-inf; fo(i,1,A) scanf("%d %d %lld",&a[i].u,&a[i].v,&a[i].w); sort(a+1,a+A+1,cmp); int cn=0; ll ans=0; fo(i,1,A) if(!check(a[i].u,a[i].v)){ cn++,ans+=a[i].w,va[i+n]=a[i].w; link(a[i].u,i+n),link(i+n,a[i].v); if(cn==n-1) break; } fo(i,1,B) scanf("%d %d %lld",&b[i].u,&b[i].v,&b[i].w); sort(b+1,b+B+1,cmp); fo(i,1,n) fat[i]=i; cn=0; fo(i,1,B) { int fx=getfa(b[i].u),fy=getfa(b[i].v); if(fx!=fy) { fat[fy]=fx; b[++cn]=b[i]; if(cn==n-1) break; } } fo(i,1,cn) { int u=b[i].u,v=b[i].v,w=b[i].w; int t=query(u,v); if(t<=n) continue; z[++tot]=w-va[t]; cut(a[t-n].u,t),cut(t,a[t-n].v); link(u,v); } sort(z+1,z+tot+1); fo(i,1,q) scanf("%d",&Q[i].x),Q[i].t=i; sort(Q+1,Q+q+1,cmp2); int pos=0; ll tmp=0; fo(i,1,q) { while(pos<tot && z[pos+1]<=Q[i].x*2) pos++,tmp+=z[pos]; an[Q[i].t]=ans+tmp+(ll)(n-1-pos)*Q[i].x-(ll)pos*Q[i].x; } fo(i,1,q) printf("%lld\n",an[i]);}
阅读全文
1 0
- 【JZOJ5433】图
- 【JZOJ5433】【NOIP2017提高A组集训10.28】图
- jzoj5433 【NOIP2017提高A组集训10.28】图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- 图
- STM32CubeMX学习:基本定时器
- 3468 A Simple Problem with Integers
- android MVVM开发框架——(3)DataBinding 应用于RecyclerView
- 快速排序算法总结
- 【git 使用详解(4)】-- 初体验
- 【JZOJ5433】图
- eclipse git报错git The current branch is not configured for pull No value for key branch.master.merge
- HDOJ 1215 七夕节
- Linux中的自动安装脚本
- 2017-10-31每日一练
- 刷题——5.5
- LeetCode 121: Best Time to Buy and Sell Stock
- 批处理作业问题——分支限界法
- 重命名UE4项目