zoukankan      html  css  js  c++  java
  • BZOJ2042 : [2009国家集训队]Will的烦恼

    不难发现题中过程对应着动态维护关于$C$的最大生成树。

    为了让$D$最大,同时让字典序最大,那么最后得到的一定是按$pair(C,D,编号)$排序的最大生成树。

    对于每条非树边$(u,v,C)$,那么它要早于树上$u$到$v$路径上任意一条同$C$值的边出现。

    而非树边之间显然不存在限制关系,因此非树边一定是按编号从小到大出现。

    从大到小考虑每条非树边,在树上找到$u,v$向上最近的同$C$值的边,然后暴力往上染色到LCA,加入限制关系。

    找往上最近的同$C$值的边可以通过离线dfs一遍树,维护每个$C$最近出现的位置来得到。

    暴力染色可以通过并查集路径压缩来优化时间复杂度。

    找到所有$O(m)$条限制关系后,用堆贪心求出字典序最小的解即可。

    时间复杂度$O(mlog m)$。

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    const int N=50010,M=100010,BUF=3500000;
    char Buf[BUF],*buf=Buf;
    inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
    int n,m,i,j,k,f[N],g[N],v[N<<1],w[N<<1],nxt[N<<1],ed;bool on[M];
    int G[M],V[M<<1],W[M<<1],NXT[M<<1],ED,q[M][2];bool d[M];
    int vis[M],c[N],fa[N],st[N],en[N],dfn,fin[M],tot;
    priority_queue<int,vector<int>,greater<int> >Q;
    struct E{int x,y,c,d,p;}e[M],a[M];
    inline bool cmp(const E&a,const E&b){
      if(a.c!=b.c)return a.c<b.c;
      if(a.d!=b.d)return a.d<b.d;
      return a.p<b.p;
    }
    int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
    inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
    inline void addq(int x,int y,int z){V[++ED]=y;W[ED]=z;NXT[ED]=G[x];G[x]=ED;}
    void dfs(int x,int y){
      st[x]=++dfn;
      fa[x]=vis[a[c[x]].c];
      f[x]=x;
      vis[a[c[x]].c]=x;
      for(int i=G[x];i;i=NXT[i])if(W[i]<0)q[-W[i]][0]=vis[V[i]];else q[W[i]][1]=vis[V[i]];
      for(int i=g[x];i;i=nxt[i])if(v[i]!=y)c[v[i]]=w[i],dfs(v[i],x);
      vis[a[c[x]].c]=fa[x];
      en[x]=dfn;
    }
    inline void ADD(int x,int y){d[V[++ED]=y]=1;NXT[ED]=G[x];G[x]=ED;}
    inline bool have(int x,int y){return st[x]<=st[y]&&en[y]<=en[x];}
    inline void col(int x,int y,int p){
      for(int i=0;i<2;i++)for(int o=q[p][i];;f[o]=fa[o]){
        o=F(o);
        if(have(o,x)&&have(o,y))break;
        ADD(p,c[o]);
      }
    }
    int main(){
      fread(Buf,1,BUF,stdin);read(n),read(m);
      for(i=1;i<=m;i++)read(e[i].x),read(e[i].y),read(e[i].c),read(e[i].d),e[i].p=i;
      sort(e+1,e+m+1,cmp);
      for(i=1;i<=m;i=j){
        for(j=i;j<=m&&e[i].c==e[j].c;j++);
        for(k=i;k<j;k++)e[k].c=i;
      }
      for(i=1;i<=n;i++)f[i]=i;
      for(i=m;i;i--)if(F(e[i].x)!=F(e[i].y)){
        on[e[i].p]=1;
        f[f[e[i].x]]=f[e[i].y];
        add(e[i].x,e[i].y,e[i].p);
        add(e[i].y,e[i].x,e[i].p);
      }
      for(i=1;i<=m;i++)a[e[i].p]=e[i];
      for(i=m;i;i--)if(!on[i]){
        addq(a[i].x,a[i].c,-i);
        addq(a[i].y,a[i].c,i);
      }
      for(i=0;i<=m;i++)vis[i]=1;
      dfs(1,0);
      for(ED=0,i=1;i<=m;i++)G[i]=0;
      for(i=m;i;i--)if(!on[i])col(a[i].x,a[i].y,i);
      for(i=1;i<=m;i++)if(!d[i])Q.push(i);
      while(!Q.empty()){
        fin[++tot]=i=Q.top();Q.pop();
        for(j=G[i];j;j=NXT[j])Q.push(V[j]);
      }
      for(i=1;i<=tot;i++)printf("%d%c",fin[i],i<tot?' ':'
    ');
      return 0;
    }
    

      

  • 相关阅读:
    Java命令行启动jar包更改默认端口以及配置文件的几种方式
    Windows下带配置文件的mysql命令行安装方法
    Windows下mysql主从搭建
    Windows下mysql集群搭建
    CAP原则(CAP定理)、BASE理论(精简)
    进程间通讯的7种方式
    Go Web 编程之 数据库
    Go 每日一库之 fsnotify
    Go 每日一库之 viper
    Go 每日一库之 go-ini
  • 原文地址:https://www.cnblogs.com/clrs97/p/7386210.html
Copyright © 2011-2022 走看看