qzezoj 1750 国王饮水记

    科技2022-08-14  110

    当然这道题可以跑最小生成树。 但是那样时间复杂度是 O ( n m α ( n ) ) O(nmα(n)) O(nmα(n)),可以被卡掉。 这里有一个跑不满 O ( n m ) O(nm) O(nm)的 就是每次拿到一条边,就搜索是否联通。 不连通就加上去 联通就找到最大的那条边,看看能不能替换,能换就换。 代码实现:

    #include<cstdio> #include<cstring> #define max(a,b) ((a)>(b)?(a):(b)) using namespace std; int n,m,k,x,y,z,nowx,nowy,flags,flag,cur; long long ans,nowans; struct yyy{int to,w,z,flag;}tmp; struct ljb{ int head,h[100039]; yyy f[200039]; inline void add(int x,int y,int z){ f[++head]=(yyy){y,z,h[x],0}; h[x]=head; } }s; inline void dfs(int x,int last,int w){ if(x==y) flag=w; if(flag) return; yyy tmp; for(cur=s.h[x];~cur;cur=tmp.z){ tmp=s.f[cur]; if(!tmp.flag&&tmp.to!=last)dfs(tmp.to,x,max(w,tmp.w)); } } inline void dfs2(int x,int last,int w){ if(x==y) flags=w; if(flags) return; yyy tmp; for(cur=s.h[x];~cur;cur=tmp.z){ tmp=s.f[cur]; if(!tmp.flag&&tmp.to!=last){ if(tmp.w==flag) {nowx=tmp.to,nowy=x;} dfs2(tmp.to,x,max(w,tmp.w)); if(flags){ if(tmp.w==flag) {nowx=tmp.to,nowy=x;} return; } } } } inline void dfss(int x,int last){ nowans++; yyy tmp; for(int cur=s.h[x];~cur;cur=tmp.z){ tmp=s.f[cur]; if(!tmp.flag&&tmp.to!=last) dfss(tmp.to,x); } } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); memset(s.h,-1,sizeof(s.h)); register int i; scanf("%d%d",&n,&m); while(m--){ scanf("%d%d%d",&x,&y,&z); flag=0; dfs(x,0,0); if(flag>z||!flag){ if(!flag) {ans+=z;s.add(x,y,z);s.add(y,x,z);} else{ flags=0;nowx=nowy=0; dfs2(x,0,0); cur=s.h[nowx]; while(~cur){ tmp=s.f[cur]; if(tmp.to==nowy&&!tmp.flag) {s.f[cur].flag=1;break;} cur=tmp.z; } cur=s.h[nowy]; while(~cur){ tmp=s.f[cur]; if(tmp.to==nowx&&!tmp.flag){s.f[cur].flag=1;break;} cur=tmp.z; } ans+=z-flag;s.add(x,y,z);s.add(y,x,z); } } nowans=0; dfss(1,0); printf("%lld %lld\n",ans,nowans); } }
    Processed: 0.020, SQL: 8