zoukankan      html  css  js  c++  java
  • 「ABC 218」解集

    E

    倒流一下,然后把负权边置零后跑 MST 即可。

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int N=2e5+5,M=2e5+5;
    struct edge
    {
    	int u,v;
    	long long w;
    	edge(int U=0,int V=0,int W=0)
    	{
    		u=U;
    		v=V;
    		w=W;
    	}
    }tur[M];
    int n,m,fa[N];
    bool cmp(edge one,edge ano)
    {
    	return one.w<ano.w;
    }
    int find(int u)
    {
    	if(u^fa[u])	fa[u]=find(fa[u]);
    	return fa[u];
    }
    long long spannin()
    {
    	long long res=0;
    	for(int i=1;i<=m;++i)
    	{
    		int u=tur[i].u,v=tur[i].v;
    		long long w=tur[i].w;
    		int x=find(u),y=find(v);
    		if(x^y)
    		{
    			fa[x]=y;
    			res+=w;
    		}
    	}
    	return res;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	long long sum=0;
    	for(int i=1;i<=n;++i)	fa[i]=i;
    	for(int i=1,u,v;i<=m;++i)
    	{
    		scanf("%d%d%lld",&u,&v,&tur[i].w);
        tur[i].w=max(tur[i].w,0LL);
    		tur[i]=edge(u,v,tur[i].w);
    		sum+=tur[i].w;
    	}
    	sort(tur+1,tur+1+m,cmp);
    	printf("%lld
    ",sum-spannin());
    	return 0;
    }
    

    F

    跑出原图的最短路树,非树边删除不需要考虑,树边就重新跑一次最短路(规模 (Theta(n)))。

    类似的题(原题)有 JOI 2020 Final Olympic Bus。

    #include<bits/stdc++.h>
    int n,m,hd[500],ecnt,ont[319300],pre[500],ide[500];
    struct edge {
      int nxt,to;
    }e[319300];
    void add_edge( int x,int y ) { e[++ecnt]={hd[x],y},hd[x]=ecnt; }
    int dis[500],vis[500];
    std::priority_queue<std::pair<int,int>,std::vector<std::pair<int,int>>,std::greater<std::pair<int,int>>> pq;
    int find( int X ) {
      std::memset( dis+1,0x3f,n<<2 );
      std::memset( vis+1,0,n<<2 );
      for( dis[1]=0,pq.emplace( 0,1 ); pq.size(); ) {
        int x=pq.top().second; pq.pop();
        if( vis[x] ) continue; vis[x]=1;
        for( int i=hd[x]; i; i=e[i].nxt ) {
          if( i==X ) continue;
          int y=e[i].to;
          if( dis[y]>dis[x]+1 ) {
            dis[y]=dis[x]+1;
            pre[y]=x;
            ide[y]=i;
            if( !vis[y] ) pq.emplace( dis[y],y );
          }
        }
      }
      return dis[n]==0x3f3f3f3f?-1:dis[n];
    }
    signed main() {
      scanf( "%d%d",&n,&m );
      for( int i=1,x,y; i<=m; ++i ) scanf( "%d%d",&x,&y ),add_edge( x,y );
      int ret=find( -1 );
      if( ret==-1 ) {
        for( int i=1; i<=m; ++i ) puts( "-1" );
        return 0;
      }
      for( int now=n; now!=1; ) ont[ide[now]]=1,now=pre[now];
      for( int i=1; i<=m; ++i ) {
        if( ont[i] ) printf( "%d
    ",find( i ) );
        else printf( "%d
    ",ret );
      }
      return 0;
    }
    

    G

    其实五分钟能冲出来的……去了板子码长 800B。

    跑出每个结点到根的中位数,这个随便拿个数据结构维护下就行了,然后做个树 DP,就考虑深度奇偶性,和 P7443 的那个 SG 函数一个套路。注意是自底向上跑的。

    #include<bits/stdc++.h>
    struct btree {
      int ch[100100][2],fa[100100],val[100100],cnt[100100],sz[100100],tot,root;
      btree() { ins( std::numeric_limits<int>::max() ),ins( std::numeric_limits<int>::min() ); }
      bool wis( int p ) { return ch[fa[p]][1]==p; }
      void pull( int p ) { sz[p]=sz[ch[p][0]]+sz[ch[p][1]]+cnt[p]; }
      int dot( int v ) { return val[++tot]=v,sz[tot]=cnt[tot]=1,tot; }
      void link( int f,int p,int k ) { ch[f][k]=p,fa[p]=f; }
      void rot( int p ) {
        int f=fa[p],gf=fa[fa[p]],k=wis( p );
        link( gf,p,wis( f ) ),link( f,ch[p][k^1],k ),link( p,f,k^1 );
        pull( f ),pull( p );
      }
      void splay( int p,int t ) {
        for( ; fa[p]!=t; rot( p ) )
          if( fa[fa[p]]!=t ) rot( wis( p )!=wis( fa[p] )?p:fa[p] );
        if( t==0 ) root=p;
      }
      int find( int v ) {
        int p=root;
        if( !p ) return 0;
        while( ch[p][v>val[p]] && v!=val[p] ) p=ch[p][v>val[p]];
        return splay( p,0 ),p;
      }
      void ins( int v ) {
        int p=root,f=0;
        while( p && v!=val[p] ) f=p,p=ch[p][v>val[p]];
        if( p ) cnt[p]++;
        else fa[p=dot(v)]=f,( f && ( ch[f][v>val[f]]=p ) );
        splay( p,0 );
      }
      int boundary( int v,int f ) { // f: 0 - pre, 1 - suf
        int p=find( v );
        if( ( val[p]>v && f ) || ( val[p]<v && !f ) ) return p;
        p=ch[p][f];
        while( ch[p][f^1] ) p=ch[p][f^1];
        return p;
      }
      void del( int v ) {
        int pre=boundary( v,0 ),suf=boundary( v,1 );
        splay( pre,0 ),splay( suf,pre );
        if( cnt[ch[suf][0]]>1 ) cnt[ch[suf][0]]--,pull( suf ),splay( ch[suf][0],0 );
        else ch[suf][0]=0,pull( suf ),splay( suf,0 );
      }
      int id( int i ) {
        int p=root; i++;
        if( sz[p]<i ) return -1;
        while( 233 ) {
          if( sz[ch[p][0]]+cnt[p]<i ) i-=sz[ch[p][0]]+cnt[p],p=ch[p][1];
          else if( sz[ch[p][0]]<i ) return val[p];
          else p=ch[p][0];
        }
        return -1;
      }
    }tr;
    int n,a[100100],med[100100],dp[100100];
    std::vector<int> g[100100];
    void dfs( int x,int f,int d ) {
      tr.ins( a[x] );
      if( d&1 ) med[x]=tr.id( ( d+1 )/2 );
      else med[x]=( tr.id( d/2 )+tr.id( d/2+1 ) )/2;
      for( int y:g[x] ) if( y!=f ) dfs( y,x,d+1 );
      tr.del( a[x] );
    }
    void DP( int x,int f,int d ) {
      int leaf=1,mx=0,mn=1e9;
      for( int y:g[x] ) if( y!=f && ( leaf=0 )^1 )
        DP( y,x,d+1 ),mx=std::max( mx,dp[y] ),mn=std::min( mn,dp[y] );
      if( leaf ) dp[x]=med[x];
      else dp[x]=( d&1 )?mx:mn;
    }
    signed main() {
      scanf( "%d",&n ); for( int i=1; i<=n; ++i ) scanf( "%d",&a[i] );
      for( int i=1,x,y; i<n; ++i ) scanf( "%d%d",&x,&y ),g[x].emplace_back( y ),g[y].emplace_back( x );
      dfs( 1,0,1 ),DP( 1,0,1 ),printf( "%d
    ",dp[1] );
      return 0;
    }
    

    H 不会 wqs / 反悔贪心,改天学下再说吧……

    是不是有点水了呀……

  • 相关阅读:
    软件工程双人项目代码规范
    《单元测试之道Java版》读后感
    《凌波微步:软件开发警戒案例集》读后感
    第一次博客作业
    认识Python
    认识JDK和JVM
    C-结构体
    C-字符串和除法
    C-指针和malloc函数
    求一个字符串没有重复字符的最大子串长度
  • 原文地址:https://www.cnblogs.com/orchid-any/p/15257651.html
Copyright © 2011-2022 走看看