jzoj【NOIP2017提高A组集训10.28】图
2017-12-08 22:20
246 查看
题目
Time Limits: 2500 ms Memory Limits: 524288 KB Detailed LimitsDescription
有一个n个点A+B条边的无向连通图,有一变量x,每条边的权值都是一个关于x的简单多项式,其中有A条边的权值是k+x,另外B条边的权值是k-x,如果只保留权值形如k+x的边,那么这个图仍是一个连通图,如果只保留权值形如k-x的边,这个图也依然是一个连通图。
给出q组询问,每组询问给出x的值,问此时这个无向连通图的最小生成树权值是多少。
Input
第一行四个数n,A,B和q
接下来A行,每行三个整数u,v,k,表示u和v之间有一条权值为k+x的无向边
接下来B行,每行三个整数u,v,k,表示u和v之间有一条权值为k-x的无向边
接下来q行,每行一个整数v,问当x=v时图的最小生成树权值是多少
Output
输出共q行,每行一个数表示对应询问的答案
Sample Input
5 4 4 4
1 3 2
1 2 0
3 5 5
3 4 10
5 4 7
2 3 6
1 2 1000
3 4 1000
0
1
2
3
Sample Output
14
16
18
18
Data Constraint
对于30%的数据,1<=n,q<=1000,n-1<=A,B<=2000
对于另外20%的数据,所有权值形如k+x的边的k满足,0<=k<=10^8,所有权值形如k-x的边的k满足9*10^8<=k<=10^9,所有询问的v满足0<=v<=4*10^8
对于另外40%的数据,1<=n<=1000,1<=q<=100000,n-1<=A,B<=2000
对于100%的数据,1<=n,q<=100000 , n-1<=A,B<=200000, 0<=k<=10^9 , -10^9<=v<=10^9
题解
这一道题一开始没有想的太清楚就照着题解打了,结果打完之后改了超级久,最后还是自己yy出了自己错误想法的一个反例才把做法更正过来。。。首先有一个很显然的结论:每一个时刻的边都是由两类边的最小生成树中的边构成的(反证,如果有一条不是这样的边那么在连接这一条边之前两点对应的联通块之间必定有最小生成树中的边相连)
当x–>-∞时我们所有的边都是正边,x–>∞时都是负边,也就是说我们可以把询问排序,然后就变成了一个负边不断的代替正边的过程。
那么我们可以先把正图的最小生成树设为当前树,然后从小到大往里面加负最小生成树里面的边,这里有一点需要注意:不一定是边权小的负边先加到图里面(见样例)但是呢当两条负图中的边在新图之中的最大的边是同一条边是显然k值小的会去替换那条边
所以我们就可以这样子把每一个替换边的x值算出来,然后我们就可以计算答案了
贴代码
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #define fo(i,a,b) for(i=a;i<=b;i++) #define fo1(i,b,a) for(i=b;i>=a;i--) #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) #define ll long long using namespace std; const int maxn=1e6+5; struct P{ int x,y,z; }a[maxn],b[maxn]; struct S{ ll x,y,z; }q[maxn],v[maxn]; int fa[maxn],father[maxn],son[maxn][3],key[maxn],mx[maxn]; int d[maxn]; bool bz[maxn]; int i,j,k,l,m,n,A,B,Q,x,y,o,js; ll ans,t1,t2,s; ll an[maxn]; char ch; int read(){ int x=0,y=1; ch=getchar(); while (ch<'0' || ch>'9'){ if (ch=='-') y=-1; ch=getchar(); } while (ch>='0' && ch<='9'){ x=x*10+ch-48; ch=getchar(); } return x*y; } int cmp(P x,P y){ return x.z<y.z; } int cmp1(S x,S y){ return x.x<y.x; } int getfather(int x){ if (father[x]==x) return x; else father[x]=getfather(father[x]); return father[x]; } bool isroot(int x){ if (son[fa[x]][1]!=x && son[fa[x]][2]!=x) return true; else return false; } void remark(int x){ if (bz[x]==true){ bz[x]=false; bz[son[x][1]]^=1; bz[son[x][2]]^=1; int t=son[x][1]; son[x][1]=son[x][2]; son[x][2]=t; } } void update(int x){ if (key[mx[son[x][1]]]>key[mx[son[x][2]]]) mx[x]=mx[son[x][1]]; else mx[x]=mx[son[x][2]]; if (key[x]>key[mx[x]]) mx[x]=x; } void rotate(int x,int w){ int y=fa[x]; son[y][3-w]=son[x][w]; if (son[x][w]) fa[son[x][w]]=y; if (!isroot(y)){ if (son[fa[y]][1]==y) son[fa[y]][1]=x; else son[fa[y]][2]=x; } fa[x]=fa[y]; fa[y]=x; son[x][w]=y; update(y); update(x); } void splay(int x){ int i,y; d[0]=0; while (!isroot(x)){ d[++d[0]]=x; x=fa[x]; } d[++d[0]]=x; fo1(i,d[0],1) remark(d[i]); x=d[1]; while (!isroot(x)){ y=fa[x]; if (isroot(y)){ if (x==son[y][1]) rotate(x,2); else rotate(x,1); } else{ if (son[fa[y]][1]==y){ if (x==son[y][1]){ rotate(y,2); rotate(x,2); } else{ rotate(x,1); rotate(x,2); } } else{ if (x==son[y][2]){ rotate(y,1); rotate(x,1); } else{ rotate(x,2); rotate(x,1); } } } } } void access(int x){ for(int t=0;x;x=fa[x]) splay(x),son[x][2]=t,update(x),t=x; } void makeroot(int x){ access(x); splay(x); bz[x]^=1; } void link(int x,int y){ makeroot(x); fa[x]=y; } void cut(int x,int y){ makeroot(x); access(y); splay(y); son[y][1]=0; fa[x]=0; update(y); } void geng(int x){ cut(a[x].x,x+n); cut(a[x].y,x+n); link(b[i].x,i+n+A); link(b[i].y,i+n+A); } int find(int x,int y){ makeroot(x); access(y); splay(y); // if (key[mx[y]]==key[0]) return -1; return (mx[y]-n); } void Link(int x,int y){ key[x+n]=y; mx[x+n]=x+n; link(a[x].x,x+n); link(a[x].y,x+n); } int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); n=read(); A=read(); B=read(); Q=read(); fo(i,1,A){ a[i].x=read(); a[i].y=read(); a[i].z=read(); } fo(i,1,B){ b[i].x=read(); b[i].y=read(); b[i].z=read(); } sort(a+1,a+A+1,cmp); sort(b+1,b+B+1,cmp); fo(i,1,n) father[i]=i; m=0; memset(key,128,sizeof(key)); fo(i,1,A){ x=getfather(a[i].x); y=getfather(a[i].y); if (x==y) continue; m++; Link(i,a[i].z); father[x]=y; s=a[i].z; ans+=s; if (m==n-1) break; } m=0; fo(i,1,n) father[i]=i; fo(i,1,B){ if (js==n-1) break; x=getfather(b[i].x); y=getfather(b[i].y); if (x==y) continue; father[x]=y; js++; o=find(b[i].x,b[i].y); v[++m].x=(b[i].z-a[o].z)/2; if (b[i].z-a[o].z>0 && ((b[i].z-a[o].z)%2)==1) v[m].x++; v[m].y=a[o].z; v[m].z=b[i].z; geng(o); } sort(v+1,v+m+1,cmp1); fo(i,1,Q){ q[i].x=read(); q[i].y=i; } sort(q+1,q+Q+1,cmp1); m=0; fo(i,1,Q){ while (q[i].x>=v[m+1].x && m<n-1){ m++; ans=ans-v[m].y+v[m].z; } s=n-2*m-1; an[q[i].y]=ans+s*q[i].x; } fo(i,1,Q) printf("%lld\n",an[i]); return 0; }
相关文章推荐
- [置顶] 【JZOJ5433】【NOIP2017提高A组集训10.28】图
- jzoj5410【NOIP2017提高A组集训10.22】小型耀斑
- 【NOIP2017提高A组集训10.28】图
- 【JZOJ 5431】【NOIP2017提高A组集训10.28】序列操作
- 【NOIP2017提高A组集训10.28】图
- 【JZOJ 5433】【NOIP2017提高A组集训10.28】图
- JZOJ. 5421【NOIP2017提高A组集训10.25】嘟嘟噜
- JZOJ 5409【NOIP2017提高A组集训10.21】Fantasy(主席树版)
- 【JZOJ 5432】【NOIP2017提高A组集训10.28】三元组
- 决策单调性的利用 jzoj5427【NOIP2017提高A组集训10.25】吃草
- jzoj5432【NOIP2017提高A组集训10.28】三元组
- 【NOIP2017提高A组集训10.28】序列操作
- 【JZOJ5431】【NOIP2017提高A组集训10.28】序列操作
- JZOJ 5432. 【NOIP2017提高A组集训10.28】三元组
- 【JZOJ5432】【NOIP2017提高A组集训10.28】三元组
- 【NOIP2017提高A组集训10.28】序列操作
- jzoj5417【NOIP2017提高A组集训10.24】方阵
- 【NOIP2017提高A组集训10.28】三元组
- jzoj5439【NOIP2017提高A组集训10.31】Calculate
- JZOJ 5431. 【NOIP2017提高A组集训10.28】序列操作