1. 程式人生 > >bzoj 4484 [Jsoi2015]最小表示——bitset

bzoj 4484 [Jsoi2015]最小表示——bitset

www 遞增 mes style http pri push lin 都是

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=4484

每個點上存一下它到每個點的連通性。用 bitset 的話空間就是 \( \frac{n^2}{8} \) 左右。

按拓撲序從大到小枚舉每個點。對於每個點判斷它的哪些出邊能刪。然後就不太會了。

其實它的出邊也不是都是等價的。連向 “拓撲序較小的點” 的出邊價值更高。因為能刪邊的情況是 u->x->v && u->v 。

所以按指向的點拓撲序遞增的順序枚舉出邊,用 bitset 看看加上這條邊對於連通性有無影響即可。

#include<cstdio>
#include
<cstring> #include<algorithm> #include<bitset> #include<queue> using namespace std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>9||ch<0){if(ch==-)fx=0;ch=getchar();} while(ch>=0&&ch<=9)ret=ret*10+ch-0,ch=getchar(); return fx?ret:-ret; }
const int N=3e4+5,M=1e5+5; int n,m,hd[N],xnt,to[M],nxt[M],dg[N],tot,a[N],dfn[N],tp[N]; bitset<N> dp[N],tmp; queue<int> q; bool cmp(int u,int v){return dfn[u]<dfn[v];} void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;dg[y]++;} int main() { n=rdn();m=rdn(); for(int i=1,u,v;i<=m;i++) u
=rdn(),v=rdn(),add(u,v); for(int i=1;i<=n;i++)if(!dg[i])q.push(i); while(q.size()) { int k=q.front(); q.pop(); dfn[k]=++tot; a[tot]=k; for(int i=hd[k],v;i;i=nxt[i]) if(--dg[v=to[i]]==0)q.push(v); } int ans=0; for(int i=n;i;i--) { int cr=a[i],p=0; for(int j=hd[cr];j;j=nxt[j]) tp[++p]=to[j]; sort(tp+1,tp+p+1,cmp); for(int j=1;j<=p;j++) { int v=tp[j]; if((dp[cr]|dp[v])==dp[cr])ans++; else dp[cr]|=dp[v]; } dp[cr][cr]=1;// } printf("%d\n",ans); return 0; }

bzoj 4484 [Jsoi2015]最小表示——bitset