BZOJ 1924 所驼门王的宝藏(强连通分量缩点+DAG最长链)
思路不是很难,因为宝藏只会在给出的n个点内有,于是只需要在这n个点里面连边,一个点如果能到达另一个点则连一条有向边,
这样用强连通分量缩点后答案就是DAG的最长链。
问题在于暴力建图是O(n^2)的,需要进行优化。
但是这n个点只有三种特殊的点,首先,同一行的点如果类型都是1显然构成了一个强连通分量,那么只需要在他们之间连n-1条双向边即可。
同理,同一列也是这样。如果同一行类型不相同则只需要从这个强连通分量的任意点向这个点连有向边即可。
因此处理同行同列的点连边时,可以用一次排序来完成。
对于第三个类型的点,也可以用map来完成。
因此总的时间复杂度为 建图O(nlogn)+强连通分量缩点O(n)+DAG最长链O(n)~O(nlogn).
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <bitset> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-8 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int N=100005; //Code begin... struct Node{int x, y, flag, id;}node[N]; struct Edge{int p, next;}edge[N*50]; int head[N], cnt=1, row[N*10], col[N*10], ps[8][2]={0,1,0,-1,1,0,-1,0,1,-1,1,1,-1,-1,-1,1}; map<PII,int>vis; int dee[N], dp[N]; int Low[N], DFN[N], Stack[N], Belong[N], Index, top, scc, num[N]; bool Instack[N]; VI E[N]; void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;} bool comp1(Node a, Node b){ if (a.x==b.x) return a.flag==1; return a.x<b.x; } bool comp2(Node a, Node b){ if (a.y==b.y) return a.flag==2; return a.y<b.y; } void Tarjan(int u){ int v; Low[u]=DFN[u]=++Index; Stack[top++]=u; Instack[u]=true; for (int i=head[u]; i; i=edge[i].next) { v=edge[i].p; if (!DFN[v]) { Tarjan(v); if (Low[u]>Low[v]) Low[u]=Low[v]; } else if (Instack[v]&&Low[u]>DFN[v]) Low[u]=DFN[v]; } if (Low[u]==DFN[u]) { ++scc; do{ v=Stack[--top]; Instack[v]=false; Belong[v]=scc; num[scc]++; }while (v!=u); } } void solve(int n){ mem(DFN,0); mem(Instack,false); mem(num,0); Index=scc=top=0; FOR(i,1,n) if (!DFN[i]) Tarjan(i); } int dfs(int x){ if (~dp[x]) return dp[x]; dp[x]=num[x]; FO(i,0,E[x].size()) { int v=E[x][i]; dp[x]=max(dp[x],num[x]+dfs(v)); } return dp[x]; } int main () { int n, R, C; scanf("%d%d%d",&n,&R,&C); FOR(i,1,n) scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].flag), node[i].id=i, vis[mp(node[i].x,node[i].y)]=i; sort(node+1,node+n+1,comp1); FOR(i,1,n) { if (row[node[i].x]) { add_edge(row[node[i].x],node[i].id); if (node[i].flag==1) add_edge(node[i].id,row[node[i].x]); } if (node[i].flag==1) row[node[i].x]=node[i].id; } sort(node+1,node+n+1,comp2); FOR(i,1,n) { if (col[node[i].y]) { add_edge(col[node[i].y],node[i].id); if (node[i].flag==2) add_edge(node[i].id,col[node[i].y]); } if (node[i].flag==2) col[node[i].y]=node[i].id; if (node[i].flag==3) { FO(j,0,8) { int dx=node[i].x+ps[j][0],dy=node[i].y+ps[j][1]; if (vis.find(mp(dx,dy))==vis.end()) continue; add_edge(node[i].id,vis[mp(dx,dy)]); } } } solve(n); vis.clear(); FOR(i,1,n) { int u=Belong[i]; for (int j=head[i]; j; j=edge[j].next) { int v=Belong[edge[j].p]; if (u==v||vis.find(mp(u,v))!=vis.end()) continue; E[u].pb(v); vis[mp(u,v)]=1; ++dee[v]; } } int ans=0; mem(dp,-1); FOR(i,1,scc) if (!dee[i]) ans=max(ans,dfs(i)); printf("%d\n",ans); return 0; }