開始就感覺是 二分圖
然後就棄t1後就一直想一直想
然而也沒想出來
暴力都沒法打啊......
題解確實是二分圖 演算法四的優化也是非常神!!! 神的到現在也沒看懂.....
60:
#include#include#include#include#includeusing namespace std;
const int n=800000;
struct h
e[n*2];
int first[n],dfn[n],low[n],stk[n],v[n],bl[n],d[n];
int top,num,tot,cnt,ti,p,q,n,m,x,y,z,ans[n],c[n];
vector>v[n];
vectore[n];
void add(int x,int y)
; first[x]=tot;
if(tot&1) add(y^1,x^1);
}void dfs(int x)
else if(v[e[i].x])
low[x]=min(low[x],dfn[e[i].x]);
if(low[x]==dfn[x])
}void f()
for(int i=2;i<=cnt;i++) dfn[bl[i]]=i;
memset(v,0,sizeof(v));
for(int i=1;i<=num;i++)
if(!v[c[i]])
v[bl[dfn[c[i]]^1]]=1;
else
for(int j=0;j<(int)
e[c[p]].size();j++)
v[e[c[p]][j]]=1;
}int main()
for(int i=1;i<=n;i++)
if(v[i].size()) add(i*2,cnt-6);
}cnt--;
for(int i=2;i<=cnt;i++)
if(!dfn[i]) dfs(i);
for(int i=1;i<=n;i++)
if(bl[i*2]==bl[i*2+1])
for(int i=2;i<=cnt;i++)
for(int j=first[i];j;j=e[j].nex)
if(bl[e[j].x]!=bl[i])
e[bl[e[j].x]].push_back(bl[i]);
for(int i=1;i<=num;i++)
for(int i=1;i<=num;i++)
for(int j=0;j<(int)e[i].size();j++)
d[e[i][j]]++;
f();
for(int i=1;i<=n;i++)
if(v[bl[i*2]])
ans[++ans[0]]=i;
printf("%d\n",ans[0]);
for(int i=1;i<=ans[0];i++) printf("%d ",ans[i]);
return 0;
}
UOJ 210 UER 6 尋找罪犯
有n個人分為好人和壞人,說了m句話。好人不會說假話,壞人至多說一句謊話。求出一組解,滿足要求。利用2 sat拆點,乙個人拆成兩個點,表示他是好人和壞人。然而這樣的話邊數是m 2的,所以用前 字尾和優化構圖即可。1 include 2 using namespace std 34 const int ...
UER 2 謠言的傳播
寫了個亂搞,怎麼莫名其妙就ac了,這.之後又想了30min結合題解終於會證了。首先最大值比較簡單,記 f i 為第 i 個點能到達的點數,上界 sum n f i 一定可以取到。考慮取到是這麼一件事情,如果 b x y 那麼 y 一定不能是 x 在外向樹上的祖先以及環上的節點,外向樹的根的前驅例外。...
UER 2 資訊的交換
吉利題.不難發現,置換中的每乙個迴圈是獨立的,每乙個迴圈分別對應乙個獨立的聯通塊。根據題目的性質,每乙個聯通塊做的事情等價於其按照編號從小到大遍歷的的dfs生成樹做的事情,那麼只需要考慮一棵dfs生成樹做的事情即可。對於一棵dfs生成樹,將每個點的兒子按照編號從小到大排序,考慮節點 u 以及它的兒子...