import java.util.*; public class Main { static final int INF=Integer.MAX_VALUE; static boolean[] used; static int flow; static int V;//頂点 static int E;//辺 static List> G;//listの二重構造で隣接リスト実現 static int N; static int M;//飛行機の便の数 static int d; static int[]u;//uから static int[]v;//Vまで飛ぶ。 static int[]p;//時刻pに離陸 static int[]q;//時刻qに到着 static int[]w;//飛行機に乗れる人数 static List>dic; static List>dic2; static int[]sz; public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ Scanner sc= new Scanner(System.in); N= sc.nextInt(); M= sc.nextInt(); d= sc.nextInt(); u= new int[M]; v= new int[M]; p= new int[M]; q= new int[M]; w= new int[M]; //dic 作成 dic= new ArrayList<>(); for(int i=0;i()); for(int i=0;i(new LinkedHashSet<>(dic));これだとダメ、多分dic.get(i)[街]のところが座圧される  dic2= new ArrayList<>(); for(int i=0;i hash= new ArrayList<>(new LinkedHashSet<>(dic.get(i))); Collections.sort(hash); dic2.add(hash); } //Gの作成 sz= new int[N];//それぞれの街の頂点の累積和を記録[個] sz[0]=dic2.get(0).size(); for(int i=1;i(); for(int i=0;i<= V;i++)G.add(new ArrayList<>());//全ての頂点を一列にした for(int i=0;i 0)start += sz[i-1]; int n= dic2.get(i).size();//個 //添字stから始まる、n個 for(int j=0;j0)startU= sz[u[i]-1]; int u_p= lower_bound(dic2.get(u[i]),p[i]);//p[i]は街u[i]の中で何番目の頂点か int from= startU+ u_p; //G.get(v[i])の位置 int startV=0; if(v[i]>0)startV= sz[v[i]-1]; int v_q= lower_bound(dic2.get(v[i]),q[i]);//q[i]は街v[i]の中で何番目の頂点か int to= startV+ v_q; add_edge(from,to,w[i]); } //max_flow int ans= max_flow(0,V-1);//sz[]はそれぞれの街の頂点の"個数"の累積和だから、0origenでは-1 System.out.println(ans); } static void add_edge(int from,int to,int cap){ G.get(from).add(new edge(to,cap,G.get(to).size())); //同時に逆辺も辿れるようにするため、に双方向に紐をつける。 G.get(to).add(new edge(from,0,G.get(from).size()-1)); } static int lower_bound(ListA,int key){ //binary_searchで実装。keyが街Aの何個目の要素か、indexを返す int left= 0; int right= A.size(); int mid; while(left< right){ mid= (left+ right)/2; if(A.get(mid) == key)return mid; if(key< A.get(mid))right= mid; if(A.get(mid)< key)left= mid+1; } return 0;//返せないことはあり得ないが、便宜上 } static int dfs(int v,int t,int f){ if(v == t)return f;//tまでたどり着いた used[v] = true; for(int i=0;i0){ int d= dfs(e.to,t,Math.min(f, e.cap)); //min(f,e.cap)はまだ流す量を決めている段階。暫定の流量 if(d>0){//tまでたどり着いた(流せる)時 //v==tのreturn fを受けて、ここで初めてf(=d)を流す e.cap -=d; G.get(e.to).get(e.rev).cap += d;//直接逆辺のcを変化させて、 return d;//各辺でdを流すために戻る。  } } } return 0; /* * tまでたどり着けなかった(途中の辺の容量が0だったのでdfs(e.to,cap,min(f,e.cap))でd=0が返ってくる) * 最初f==INFだから、d==0(f==0)の時は、全ての辺を辿ってみたけど全く流せなかったってこと * d>0に引っかからなかったとも言える */ } static int max_flow(int s,int t) { int flow= 0; while(true){ used =new boolean[V]; int f= dfs(s,t,INF); if(f == 0)return flow;//if(もうこれ以上流せない)return flow +=f; } } static class edge { int to; int cap; int rev;//逆辺にアクセスする edge(int to,int cap,int rev){ this.to =to; this.cap =cap; this.rev =rev; } } }