[luogu8291]学术社区

对所有消息建图,其中\((x,y)\)的边权为当\(x\)的下一条消息为\(y\)时的收益

具体的,图中包含以下两类边(边权为\(1\)):

  • 对于楼上消息,假设其提到的网友为\(s\),其向\(s\)发出的消息连边
  • 对于楼下消息,假设其提到的网友为\(s\)\(s\)发出的消息向其连边

另外,特殊性质\(C\)中的情况会产生重边,此时该边边权为\(2\)

此时,问题即选择边的子集,满足每个点出入度均不超过\(1\),并最大化边权和

结论1:对于重边\((x,y)\),存在一种最优方案选择该边

任取一组最优解,若未选择\((x,y)\),则分类讨论:

  • 若其中\(x\)的出边存在且边权为\(2\),则交换\(y\)和该出边端点(两者完全相同)
  • 类似的,若\(y\)的入边存在且边权为\(2\),则交换\(x\)和该入边端点
  • 否则,直接删除\(x\)的出边和\(y\)的入边,并加入\((x,y)\),显然不劣

根据此结论,可以将图中\(x\)的出边和\(y\)的入边均删除,并将最终答案\(+2\)

重复此过程,最终图中所有边的边权均为\(1\),问题也即求最小路径覆盖

结论2:将该图视作DAG求最小路径覆盖,答案不变

对于通常的有向图,该做法问题在于可能选择一个简单环

注意到简单环中总包含非学术消息(学术消息间无边),不妨假设包含楼上消息

楼上消息的入边(另一个端点)必然也为楼上消息,以此类推整个环均为楼上消息

此时,任取图中某个消息,在该处断开并插入到对应的学术消息前即可

重复上述过程,最终可得一组不包含简单环的方案,即得证

根据此结论,并简单优化建边,由于二分图至多增广\(\sqrt{m}\)次,时间复杂度为\(O(m\sqrt{m})\)

建边时使用vector会比邻接表快很多,可能是出边顺序的问题

#include<bits/stdc++.h>
using namespace std;
#define N 80000
#define M 1000000
#define ull unsigned long long
int t,n,m,a[N],b[N],c[N];ull s1,s2,s3,id[N];
int V,E,it[M],d[M];queue<int>q;struct Data{int to,len,rev;};vector<Data>e[M];
int ans,pos[N],vis[N],pre[N],nex[N];vector<int>vl,vr;map<int,vector<int> >mat1[N],mat2[N];
int change(char c){
    if ((c>='A')&&(c<='Z'))return c-'A'+1;
    if ((c>='a')&&(c<='z'))return c-'a'+27;
    if (c=='_')return 53;
    if (c=='?')return 54;
    if (c=='!')return 55;
    return (c=='.' ? 56 : 0);
}
ull read(){
    ull x=0;int c=change(getchar());
    while (!c)c=change(getchar());
    while (c)x=x*57+c,c=change(getchar());
    return x;
}
void add(int x,int y,int z){
    e[x].push_back(Data{y,z,(int)e[y].size()});
    e[y].push_back(Data{x,0,(int)e[x].size()-1});
}
bool bfs(){
    for(int i=1;i<=V;i++)d[i]=-1;
    q.push(0);
    while (!q.empty()){
        int k=q.front();q.pop();
        for(Data i:e[k])
            if ((i.len)&&(d[i.to]<0))d[i.to]=d[k]+1,q.push(i.to);
    }
    return d[V]>=0;
}
int dfs(int k,int s){
    if (k==V)return s;
    int ans=0;
    for(int &i=it[k];i<e[k].size();i++)
        if ((e[k][i].len)&&(d[e[k][i].to]==d[k]+1)){
            int p=dfs(e[k][i].to,min(s,e[k][i].len));
            e[k][i].len-=p,e[e[k][i].to][e[k][i].rev].len+=p,s-=p,ans+=p;
            if (!s)return ans;
        }
    return ans;
}
int dinic(){
    int ans=0;
    while (bfs()){
        ans+=dfs(0,0x3f3f3f3f);
        for(int i=0;i<=V;i++)it[i]=0;
    }
    return ans;
}
void link(int x,int y){
    if (nex[x])pre[nex[x]]=0;
    if (pre[y])nex[pre[y]]=0;
    nex[x]=(x ? y : 0),pre[y]=(y ? x : 0);
}
int main(){
    scanf("%d",&t);
    while (t--){
        scanf("%d%d",&n,&m);
        V=(m+n<<1)+1,E=ans=0;
        for(int i=0;i<=V;i++)it[i]=0,e[i].clear();
        for(int i=1;i<=m;i++)vis[i]=pre[i]=nex[i]=0;
        for(int i=1;i<=n;i++)mat1[i].clear(),mat2[i].clear();
        for(int i=1;i<=n;i++)id[i]=read();
        sort(id+1,id+n+1);
        for(int i=1;i<=m;i++){
            s1=read(),s2=read(),s3=read();
            a[i]=lower_bound(id+1,id+n+1,s1)-id;
            b[i]=lower_bound(id+1,id+n+1,s2)-id;
            if ((b[i]>n)||(id[b[i]]!=s2))b[i]=c[i]=0;
            else c[i]=(s3==23305962750LL ? 2 : (s3==75721020011865LL));
            if (!c[i])pos[a[i]]=i;
            if (c[i]==1){
                if (mat2[b[i]][a[i]].empty())mat1[a[i]][b[i]].push_back(i);
                else{
                    int j=mat2[b[i]][a[i]].back();
                    mat2[b[i]][a[i]].pop_back();
                    ans+=2,link(i,j),vis[i]=vis[j]=1;
                }
            }
            if (c[i]==2){
                if (mat1[b[i]][a[i]].empty())mat2[a[i]][b[i]].push_back(i);
                else{
                    int j=mat1[b[i]][a[i]].back();
                    mat1[b[i]][a[i]].pop_back();
                    ans+=2,link(j,i),vis[i]=vis[j]=1;
                }
            }
        }
        for(int i=1;i<=m;i++){
            add(0,i,1),add(i+m,V,1);
            if ((!vis[i])||(c[i]!=1))add(i,a[i]+(m<<1),1);
            if ((!vis[i])||(c[i]!=2))add(a[i]+(m<<1)+n,i+m,1);
            if ((!vis[i])&&(c[i]==1))add(i,b[i]+(m<<1)+n,1);
            if ((!vis[i])&&(c[i]==2))add(b[i]+(m<<1),i+m,1);
        }
        ans+=dinic(),printf("%d\n",ans);
        for(int i=1;i<=n;i++){
            for(Data j:e[i+(m<<1)+n])e[i+(m<<1)].push_back(j);
            for(Data j:e[i+(m<<1)]){
                if ((j.to<=m)&&(j.len)){
                    if (vr.empty())vl.push_back(j.to);
                    else link(j.to,vr.back()),vr.pop_back();
                }
                if ((j.to>m)&&(!j.len)){
                    if (vl.empty())vr.push_back(j.to-m);
                    else link(vl.back(),j.to-m),vl.pop_back();
                }
            }
        }
        for(int i=1;i<=m;i++)vis[i]=0;
        for(int i=1;i<=m;i++)
            if (!vis[i]){
                int j=i;
                while (!vis[j])vis[j]=1,j=nex[j];
                if (j==i){
                    if (c[i]==1)j=pre[i],link(pre[pos[a[i]]],i),link(j,pos[a[i]]);
                    else j=nex[i],link(i,nex[pos[a[i]]]),link(pos[a[i]],j);
                }
            }
        for(int i=1;i<=m;i++)
            if (!pre[i]){
                for(int j=i;j;j=nex[j])printf("%d ",j);
            }
        printf("\n");
    }
    return 0;
}
posted @ 2022-05-19 15:09  PYWBKTDA  阅读(80)  评论(0编辑  收藏  举报