小さな紫色の質問の良い(E)、(XIN)として、それはやって価値がある(対象ナンセンス、と実践吐き気が)
タイトル説明
幅広いアフリカの砂漠では、勤勉かつ勇敢なアルパカの家族のグループと一緒に生活。クリスティン部族がアルパカL. Sotomonは家族のリーダーであるの「預言者」として知られ、部外者とも呼ばれる「ラクダのドアの王。」ラクダのドア王は家族の安定と調和を維持するために彼の人生を捧げ、彼は個人的に部族が笑エクスプロイトを設定するために彼の軍隊は、帝国主義のカニ残忍な侵略を砕い率いていました。王Yisheng無数の宝物、しかし、その控えめな質素な自然のラクダのドアは、彼は今日ヘンリー・カーティスの物語の出発点である地下宮殿の独自のデザイン、に埋葬宝物ます。ヘンリーはお金-grubber貪欲な男であり、非常にスマートな、彼は重い臓器が、この地下宮殿の前に来たクラックするこのアクションの窃盗を計画するために苦心しました。
Nは、宮殿、宮殿と呼ばれる宝の間に隠された宝物を埋め込みあるR×C矩形宮殿、間マトリクス状に全体宮殿、。宮殿、唯一ゲート間キングオリジナルラクダの移動を介して他の宮殿によって障壁に隣接する剛性壁により相互エンティティ宮殿 - ポータル。ラクダは各部屋間のNのドアの王は宝の宮殿がポータルを建て、宮殿のすべてのポータルが3分割され、何の宝宮殿ポータルではありませんされていません。
-
「デイズ水平ドア」:宮殿のゲートは、任意の相手に送信することができます。
-
「アトラス垂直ドア」:ドアは宮殿同じ列のいずれかに送信することができます。
-
「任意の扉」:ドアはいずれ宮殿(宮殿のターゲット存在する場合)の約8グリッドの家の中心に位置するゲートに伝達されてもよいです。
ヘンリーは、今年の王の宮殿のラクダの入札書の扉を取得するには、事前に思慮深いもちろん、すべてのファンポータルのブック詳細な記録は、宮殿やタイプに属します。また、離れて内側と外側の宮殿が、彼はポータブルポータルを所有する準備ができていたものの、それがいずれかの宮殿宝探しの始まりと宮殿宮殿のうちいずれかの転送終了時に自分の会場に転送することができます。徐一度だけ全体宮殿アウト、およびポータブルドアは宮殿の間で転送することはできません。しかし、幸いなことに、制限はありません屋内宮殿ポータルの使用は、各宮殿は、複数のエントリを作成することができます。
ヘンリーは今入ろうとしている家を選択し、ドアの移植性を開きました。宝物を得るために多くを行うために、彼はできるだけ宮殿異なる宝物を通るルートを手配することを望みました。ヘンリー異なる宝宮殿の最大数を通過するルートを教えてください。
入力形式
最初の行は、3つの正の整数N、R、C. sotomon.in入力ファイルを与えます
次のN行、各行はxiとyiの宝宮殿カラム型に配置された第1列に設けられた転送ゲートは、Tiであることを示す、チタンの3つの正整数XI、YIを含む、情報ポータルを与えます。Tiは1〜3の整数であり、1が表す「クロス日ドア」のいずれかの第二XI行に送信されてもよい、2が表す任意の行のYI-カラム、3の周りを表し、「垂直アトラスドア」に移し8に送信することができますグリッドの宮殿「いずれかのドア。」
1≤xi≤R、1≤yi≤C、互いに異なるすべてのポータルの位置を確認してください。
出力フォーマット
出力ファイルは、あなたのルートが通る決定異なる宝宮殿の最大数を表すだけ正の整数をsotomon.out。
サンプル入力と出力
7 7 10 2 2 1 2 4 2 1 7 2 2 7 3 4 2 2 4 4 1 6 7 3 7 7 1 7 5 2 5 2 1
9
説明/ヒント
データ規模と規則:
--------------------------------------------分割ライン---- -------------------------------------------
一見、普通のタイトルサーチでは、取得するのは非常に簡単で、その後、剪定ばさみのように五十から六を考えます
しかし、この非常に嫌では10 ^ 6、マトリックスは、いずれかを保存することができ、データの範囲を表示するには
メイド、シンプルtarjan + DP
しかし、接続側を考えると、少しくらいのようです
その後、我々は、(Iチューン夜、また最も困難な課題である点)建設側を最適化することができます
各ドアの次に特殊ので、我々はクロス天門のための3つのアルゴリズム各行で別々の描画を構築する必要があり、我々は、各垂直列アトラスドア用リングにそれを構築し、そして我々は、にそれを構築しますリング。私たちが知っているので:
相互に各水平行の間のすべてのドアの日は確かにアクセス可能であり、各列アトラス長手方向のすべてのドアの間で確かに相互にアクセス可能です。だから私たちは言うことができます。
あなたはこのラインに到達したときに、行のクロス日間のドアに達するすべてのクロス天門、あなたは列の垂直アトラスのドアに到達したときに、この列に達するすべての垂直アトラスドア。
だから我々はリングにそれを構築することができます。Tarjanの使用が来ました。我々は、これら2つのTarjanリングがポイントに縮小使用することができます。任意のドアのために私は暴力が側より良い方法を構築するために期待していなかったので、彼は~~~暴力的な側面の友人を建てました。
それが十分でなかったなら、私たちは持っています
ソート
私たちは自然に早いほど良いので、次のようにCMPがあるので、ドアの前に空を横断しようとすると、その日がドアを横断見つけることを願っています:
ブールCMP1(ノードA、ノードB){ 場合(AX = BX!)戻り AX < BX。 もし(a.opt == 1)リターン 1 。 もし(b.opt == 1)戻り 0 ; 返す AYを< ことで、 }
だから、とき垂直アトラスは、あまりにもドアを探します。
BOOL CMP2(ノードA、ノードB){ 場合(AY =によって!)戻り AY < によって、 もし(a.opt == 2)リターン 1 。 もし(b.opt == 2)戻り 0 ; リターン斧< BX。 }
さて、私たちは順番に並んでいる、次のステップはさらに巧妙な側面では、まず、各サイクルは見つけるための最初の時間を表し、最後のAに示されています
だから、さえ側のコード:
ソート(P + 1、P +番号+ 1 、CMP1)。 最初 =最後= 1 。 以下のために(int型 i = 1 ; iは=数を<; iは++ ){ 場合(!P [i]は.X = Pは[I + 1 ] .X){ 場合(!最初= 最後)の追加(P [最終] .ID P [第] .ID)。 最初 =最後の=私は+ 1を、 } 他{ 場合(P [最終] .OPT == 1)を追加(P [最終] .ID、P [I + 1 ] .ID)。 もし(P [I + 1 ] .OPT == 1)最後= I + 1; 場合(Pは[最初] .OPT =!1)最後=最初= I + 1 。 } }
垂直ドアあまりにアトラス
だから、次のステップは、いずれかのドアがあり、我々は店のマップに使用し、(A夢を考えます)
もちろん、これは、プレイヤーは、C ++を楽しむ、他の言語は、ハッシュを使用することができますです
次のようにコードは次のとおりです。
以下のために(int型 i = 1 ; iが<=数、iは++ ){ 場合(P [i]の.OPT == 3 ){ ための(int型のk = 0 ; K < 8 ; kは++ ){ int型 NX = P [I]。 X + DX [K]、NY = P [i]は.Y + DY [K]。 もし(fh.count(PA(NX、NY))) を追加(P [i]の.ID、FH [PA(NX、NY)])。 } } }
まあ、貧しい人々の建設側の端は、その後、Tarjanでリングを探します
这个不用多说,直接上代码:
void Tarjan(int now){ low[now]=dfn[now]=++deeth;res[now]=1; q[++top]=now; for(int i=head[now];i;i=nxt[i]){ int y=ver[i]; if(!dfn[y])Tarjan(y),low[now]=min(low[now],low[y]); else if(res[y])low[now]=min(low[now],dfn[y]); } if(dfn[now]==low[now]){ color[now]=++sum;res[now]=0; while(q[top]!=now){ size[sum]++; res[q[top]]=0;color[q[top--]]=sum; } size[sum]++;top--; } }
那么最后就是一个简单的DP了:
void dfs(int now,int fa){ if(dp[now]>size[now])return; dp[now]=size[now]; for(int i=head1[now];i;i=nxt1[i]){ int y=ver1[i]; if(y==fa)continue; dfs(y,now); dp[now]=max(dp[now],dp[y]+size[now]); } } for(int i=1;i<=sum;i++){ if(in[i]==0){ dfs(i,0);ans=max(ans,dp[i]); } }
那么AC代码就是:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pa pair<int,int> 4 5 const int _=300002; 6 int number,length,wide,first,last,size[_],dp[_],in[_]; 7 int ver[_*10],head[_*10],nxt[_*10],from[_*10],tot,ans=-1; 8 int ver1[_*10],head1[_*10],nxt1[_*10],tot1; 9 int dx[9]={-1,-1,-1,0,0,1,1,1},dy[9]={-1,0,1,-1,1,-1,0,1}; 10 int color[_],sum,low[_],dfn[_],q[_],top,deeth,res[_]; 11 struct node{int x,y,opt,id;}P[_]; 12 map<pa,int>fh; 13 14 int read(){ 15 int s=0,w=1;char ch=getchar(); 16 while(ch<'0'||ch>'9')w=(ch=='-')?-1:1,ch=getchar(); 17 while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar(); 18 return s*w; 19 } 20 21 void add(int x,int y){ 22 from[++tot]=x;ver[tot]=y;nxt[tot]=head[x];head[x]=tot; 23 } 24 25 void ad(int x,int y){ 26 ver1[++tot1]=y;nxt1[tot1]=head1[x];head1[x]=tot1; 27 } 28 29 bool cmp1(node a,node b){ 30 if(a.x!=b.x)return a.x<b.x; 31 if(a.opt==1)return 1; 32 if(b.opt==1)return 0; 33 return a.y<b.y; 34 } 35 36 bool cmp2(node a,node b){ 37 if(a.y!=b.y)return a.y<b.y; 38 if(a.opt==2)return 1; 39 if(b.opt==2)return 0; 40 return a.x<b.x; 41 } 42 43 void Tarjan(int now){ 44 low[now]=dfn[now]=++deeth;res[now]=1; 45 q[++top]=now; 46 for(int i=head[now];i;i=nxt[i]){ 47 int y=ver[i]; 48 if(!dfn[y])Tarjan(y),low[now]=min(low[now],low[y]); 49 else if(res[y])low[now]=min(low[now],dfn[y]); 50 } 51 if(dfn[now]==low[now]){ 52 color[now]=++sum;res[now]=0; 53 while(q[top]!=now){ 54 size[sum]++; 55 res[q[top]]=0;color[q[top--]]=sum; 56 } 57 size[sum]++;top--; 58 } 59 } 60 61 void dfs(int now,int fa){ 62 if(dp[now]>size[now])return; 63 dp[now]=size[now]; 64 for(int i=head1[now];i;i=nxt1[i]){ 65 int y=ver1[i]; 66 if(y==fa)continue; 67 dfs(y,now); 68 dp[now]=max(dp[now],dp[y]+size[now]); 69 } 70 } 71 72 int main(){ 73 // freopen("precious.in","r",stdin); 74 // freopen("precious.out","w",stdout); 75 number=read();length=read();wide=read(); 76 for(int i=1;i<=number;i++){ 77 P[i].x=read();P[i].y=read();P[i].opt=read();P[i].id=i; 78 fh[pa(P[i].x,P[i].y)]=i; 79 } 80 //----------------------------------------------------- 81 for(int i=1;i<=number;i++){ 82 if(P[i].opt==3){ 83 for(int k=0;k<8;k++){ 84 int nx=P[i].x+dx[k],ny=P[i].y+dy[k]; 85 if(fh.count(pa(nx,ny))) 86 add(P[i].id,fh[pa(nx,ny)]); 87 } 88 } 89 } 90 //----------------------------------------------------- 91 sort(P+1,P+number+1,cmp1); 92 first=last=1; 93 for(int i=1;i<=number;i++){ 94 if(P[i].x!=P[i+1].x){ 95 if(first!=last)add(P[last].id,P[first].id); 96 first=last=i+1; 97 } 98 else{ 99 if(P[last].opt==1)add(P[last].id,P[i+1].id); 100 if(P[i+1].opt==1)last=i+1; 101 if(P[first].opt!=1)last=first=i+1; 102 } 103 } 104 //------------------------------------------------------ 105 sort(P+1,P+number+1,cmp2); 106 first=last=1; 107 for(int i=1;i<=number;i++){ 108 if(P[i].y!=P[i+1].y){ 109 if(first!=last)add(P[last].id,P[first].id); 110 first=last=i+1; 111 } 112 else{ 113 if(P[last].opt==2)add(P[last].id,P[i+1].id); 114 if(P[i+1].opt==2)last=i+1; 115 if(P[first].opt!=2)last=first=i+1; 116 } 117 } 118 //------------------------------------------------------ 119 for(int i=1;i<=number;i++) 120 if(!dfn[i])Tarjan(i); 121 for(int i=1;i<=tot;i++){ 122 int x=from[i],y=ver[i]; 123 if(color[x]==color[y])continue; 124 ad(color[x],color[y]);in[color[y]]++; 125 } 126 for(int i=1;i<=sum;i++){ 127 if(in[i]==0){ 128 dfs(i,0);ans=max(ans,dp[i]); 129 } 130 } 131 cout<<ans; 132 return 0; 133 }