[SDOI2010] 所驼门王的宝藏 [建图+tarjan缩点+DAG dp]
题面传送门:
思路:
看完题建模,容易得出是求单向图最长路径的问题
那么把这张图缩强联通分量,再在DAG上面DP即可
然而
这道题的建图实际上才是真正的考点
如果对于每一个点都直接连边到它所有的后继节点,那么可以被卡掉(1e5个点在同一行上)
考虑改变思路,运用网络流建图中的一个常用技巧:把横边和竖边映射成点,再从每个点向所在横坐标、纵坐标代表的点连边即可
这样会有2e6+1e5个点,但是tarjan算法效率O(n),完全无压力
自由(和谐)门的话,目前还没有比较好的方法解决
上网看了一圈题解,也都是排序或者map的
这里就用map
//为什么自由(和谐)门会是违规的啊......
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<map> 6 #include<vector> 7 #define mp make_pair 8 #pragma comment(linker, "/STACK:202400000,202400000") 9 using namespace std; 10 const int dx[9]={0,1,1,1,0,0,-1,-1,-1},dy[9]={0,-1,0,1,-1,1,-1,0,1}; 11 inline int read(){ 12 int re=0,flag=1;char ch=getchar(); 13 while(ch>'9'||ch<'0'){ 14 if(ch=='-') flag=-1; 15 ch=getchar(); 16 } 17 while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); 18 return re*flag; 19 } 20 int n,r,c,first[2100010],First[2100010],cnt=0,Cnt=0; 21 int dfn[2100010],low[2100010],num=0; 22 int s[2100010]={0},top=0; 23 int belong[2100010],tot=0,dp[2100010],siz[2100010],in[2100010]; 24 bool vis[2100010]; 25 int x[100010],y[100010]; 26 struct edge{ 27 int from,to,next; 28 }a[2000010]; 29 struct Edge{ 30 int to,next; 31 }e[2000010]; 32 inline void add(int u,int v){ 33 // cout<<"add "<<u<<ends<<v<<endl; 34 a[++cnt]=(edge){u,v,first[u]};first[u]=cnt; 35 } 36 inline void Add(int u,int v){ 37 e[++Cnt]=(Edge){v,First[u]};First[u]=Cnt; 38 } 39 map<pair<int,int>,int>m; 40 void tarjan(int u){ 41 // cout<<"tarjan "<<u<<endl; 42 int i,v;vis[u]=1; 43 dfn[u]=low[u]=++num; 44 s[++top]=u; 45 for(i=first[u];~i;i=a[i].next){ 46 v=a[i].to; 47 if(belong[v]) continue; 48 if(!dfn[v]){ 49 tarjan(v); 50 low[u]=min(low[u],low[v]); 51 } 52 else low[u]=min(low[u],dfn[v]); 53 } 54 if(low[u]==dfn[u]){ 55 ++tot; 56 while(s[top]!=u){ 57 belong[s[top]]=tot; 58 if(s[top]>r+c) siz[tot]++; 59 // qlt[tot].push_back(s[top]); 60 s[top--]=0; 61 } 62 belong[s[top]]=tot; 63 if(s[top]>r+c) siz[tot]++; 64 // qlt[tot].push_back(s[top]); 65 s[top--]=0; 66 } 67 } 68 int q[2100010],head=0,tail=0; 69 int main(){ 70 // freopen("sdoi10sotomon.in","r",stdin); 71 // freopen("sdoi10sotomon.out","w",stdout); 72 memset(first,-1,sizeof(first)); 73 memset(First,-1,sizeof(First)); 74 int i,t1,t2,t3,t4,t5,j,u,v,ans=0; 75 map<pair<int,int>,int>::iterator tmp; 76 memset(first,-1,sizeof(first)); 77 n=read();r=read();c=read(); 78 for(i=1;i<=n;i++){ 79 t1=read();t2=read();t3=read(); 80 x[i]=t1;y[i]=t2; 81 m[mp(t1,t2)]=i; 82 add(t1,r+c+i);add(t2+r,i+r+c); 83 if(t3==1) add(r+c+i,t1); 84 if(t3==2) add(r+c+i,r+t2); 85 if(t3==3) vis[i]=1; 86 } 87 for(i=1;i<=n;i++){ 88 if(!vis[i]) continue; 89 t1=x[i];t2=y[i]; 90 for(j=1;j<=8;j++){ 91 t3=t1+dx[j];t4=t2+dy[j]; 92 tmp=m.find(mp(t3,t4)); 93 if(tmp==m.end()) continue; 94 add(r+c+i,r+c+tmp->second); 95 } 96 } 97 memset(vis,0,sizeof(vis)); 98 for(i=1;i<=r+c+n;i++) if(!vis[i]) tarjan(i); 99 // cout<<"end of tarjan"<<endl; 100 // for(i=1;i<=r+c+n;i++) cout<<belong[i]<<ends; 101 // for(i=1;i<=tot;i++){ 102 // for(j=0;j<qlt[i].size();j++) cout<<qlt[i][j]<<ends; 103 // cout<<endl; 104 // } 105 for(i=1;i<=cnt;i++){ 106 if(!belong[a[i].from]||!belong[a[i].to]) continue; 107 if(belong[a[i].from]==belong[a[i].to]) continue; 108 Add(belong[a[i].from],belong[a[i].to]);in[belong[a[i].to]]++; 109 } 110 // cout<<"end of Add\n"; 111 for(i=1;i<=tot;i++) if(!in[i]) q[tail++]=i,dp[i]=siz[i]; 112 while(head<tail){ 113 u=q[head++]; 114 for(i=First[u];~i;i=e[i].next){ 115 v=e[i].to; 116 dp[v]=max(dp[v],dp[u]+siz[v]);in[v]--; 117 if(!in[v]) q[tail++]=v; 118 } 119 } 120 for(i=1;i<=tot;i++) ans=max(ans,dp[i]); 121 printf("%d",ans); 122 }