LUOGU P2403 [SDOI2010]所駝門王的寶藏
阿新 • • 發佈:2020-11-30
可以發現最後由 \(n\) 個點組成的圖是有環的,我們繼而進行縮點後 DP
step 1: 建圖
暴力是 \(\mathcal{O}(n^2)\) 的,優化
可以發現同一行的標號均為 1 的點可以形成環
同一列的標號均為 2 的點可以形成環
有以下思路:
先將行數排序作為第一關鍵字,將是否標號為 1 作為第二關鍵字對於點排序
取第每一行一個點作為連結串列頭,鏈上有這一行上標號為 1 的點,最後將鏈頭和鏈尾相接,就成功得到了一個環
對於這一行上標號不為 1 的點,直接上一條鏈頭到該點的邊即可
對於標號為 2 和列的處理與對於行的處理相似
對於標號為 3 的點,考慮暴力加邊,可使用std::map
step 2: 縮點 & 建 DAG
點權即為環上點的數量,其他都是板子
step 3: 拓撲排序 + DP
\(num_v\) 為點權
\[f_v = \max_{(u,v)\in DAG} f_u + num_v \]答案 \(Ans = \max f_i\)
總複雜度 \(\mathcal{O}(n\log n)\)
Code(C++):
#include<bits/stdc++.h> #define forn(i,s,t) for(int i=(s);i<=(t);++i) using namespace std; typedef long long LL; const int N = 1e5+3,Mod = 1e6+7; const int dxx[] = {1,1,1,-1,-1,-1,0,0}; const int dyy[] = {0,1,-1,1,0,-1,1,-1}; struct List { int dir,nxt; }E[N<<3],DAG[N<<3]; int G[N],cnt,G1[N],cnt1,ind[N]; inline void Add(int u,int v) { E[++cnt].dir = v,E[cnt].nxt = G[u],G[u] = cnt; } inline void AddDAG(int u,int v) { DAG[++cnt1].dir = v,DAG[cnt1].nxt = G1[u],G1[u] = cnt1,ind[v]++; } int n,R,C,id[N],x[N],y[N],t[N]; struct Hash { // 亂搞Hash LL val[N<<2]; int nxt[N<<2],id[N<<2],head[Mod+2],cnt; inline void Add(int x,int y,int nd) { LL A = 1ll*(x-1)*C+y; LL B = A%Mod; val[++cnt] = A,id[cnt] = nd,nxt[cnt] = head[B]; head[B] = cnt; } inline int Fnd(int x,int y) { LL A = (1ll*(x-1)*C+y) %Mod; LL B = 1ll*(x-1)*C+y; for(int i=head[A];i;i=nxt[i]) if(val[i] == B) return id[i]; return -1; } }H; int dfn[N],ord,stk[N],h,clr[N],col,num[N],f[N],Ans; bool vis[N]; int tarjan(int u) { int low = dfn[u] = ++ord; stk[++h] = u,vis[u] = 1; for(int i=G[u];i;i=E[i].nxt) { int v = E[i].dir; if(!dfn[v]) low = min(tarjan(v),low); else if(vis[v]) low = min(low,dfn[v]); } if(low == dfn[u]) { ++col; do num[col]++,vis[stk[h]]=0,clr[stk[h]]=col; while(stk[h--]!=u); } return low; } queue<int> q; inline bool cmp(int A,int B) {return x[A]!=x[B]?(x[A]<x[B]):((t[A]==1)?1:(!t[B]));} inline bool cmp1(int A,int B){return y[A]!=y[B]?(y[A]<y[B]):((t[A]==2)?1:(!t[B]));} int main() { scanf("%d%d%d",&n,&R,&C); forn(i,1,n) scanf("%d%d%d",&x[i],&y[i],&t[i]); forn(i,1,n) H.Add(x[i],y[i],i); /*--------建圖 part----------*/ forn(i,1,n) id[i] = i; sort(id+1,id+n+1,cmp); forn(i,1,n) if(t[id[i]] == 1) { // situation 1 int llst=i,lst=id[i],fir=id[i]; for(int j=i+1;j<=n;++j) { if(x[id[j]]!=x[id[i]]) break ; llst = j; if(t[id[j]] == 1) Add(lst,id[j]),lst = id[j]; else Add(id[i],id[j]); } if(lst^fir) Add(lst,fir); i = llst; } sort(id+1,id+n+1,cmp1); forn(i,1,n) if(t[id[i]] == 2) { // situation 2 int llst = i,lst=id[i],fir=id[i]; for(int j=i+1;j<=n;++j) { if(y[id[i]]!=y[id[j]]) break ; llst = j; if(t[id[j]] == 2) Add(lst,id[j]),lst = id[j]; else Add(id[i],id[j]); } if(lst^fir) Add(lst,fir); i = llst; } int v; forn(i,1,n) if(t[i] == 3) // situation 3 forn(j,0,7) if((v=H.Fnd(x[i]+dxx[j],y[i]+dyy[j])) != -1) Add(i,v); /*--------縮點 Part--------*/ forn(i,1,n) if(!dfn[i]) tarjan(i); forn(u,1,n) for(int i=G[u];i;i=E[i].nxt) { v = E[i].dir; if(clr[v] == clr[u]) continue ; AddDAG(clr[u],clr[v]); } /*---------DP Part-------*/ forn(i,1,col) if(!ind[i]) q.push(i),f[i] = num[i]; while(!q.empty()) { int u = q.front(); q.pop(); for(int i=G1[u];i;i=DAG[i].nxt) { v = DAG[i].dir; f[v] = max(f[v],f[u]+num[v]); if(!--ind[v]) q.push(v); } } forn(i,1,col) Ans = max(Ans,f[i]); printf("%d\n",Ans); return 0; }