/* HDU 3062 */ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #include<map> #include<algorithm> using namespace std; const int MAXE=100000002; const int MAX=6009; struct EDGE { int v; // 从u点出发能到达的点v int next; // 从u点出发能到达的下一条边的编号 }edge[MAXE]; int first[MAX]; // first[u] = e:从点u出发的最后一条边的编号是e(“最后”是指最后输入) int dfn[MAX]; // dfn[u]:节点u搜索的次序编号(时间戳) int low[MAX];// low[u]:是u或u的子树能够追溯到的最早的栈中节点的次序号 int ins[MAX];// 是否在栈中 int scc[MAX]; // scc[i] = j:第i个点所在的强连通分量的编号 (此题可有可无) int t,n,m; int num; // 强连通分量的数目 int index; // 次序编号 int s[MAX]; int top,e; int a,b,c,d,nn; int DFS(int x) { low[x]=dfn[x]=index++; s[++top]=x; ins[x]=1; // 枚举每一条边:u-->v for(int k=first[x];k!=-1;k=edge[k].next) { int v=edge[k].v; if(dfn[v]==0) { DFS(v); low[x]=min(low[x],low[v]); } else if(ins[v]) { low[x]=min(dfn[v],low[x]); } } // 如果节点u是强连通分量的根 if(low[x]==dfn[x]) { int v; num++; do{ v=s[top--]; ins[v]=0; scc[v]=num; }while(v!=x); } return 1; } inline void add(int u,int v) { edge[e].v=v; edge[e].next=first[u]; first[u]=e++; } inline int turn(int x) { return x>n?x-n:x+n; } void init() { memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(first,-1,sizeof(first)); // memset(ins,0,sizeof(ins)); index=1; top=-1; num=0; e=0; int aa,bb; for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&a,&b,&c,&d); a++; aa=a+c*n; b++; bb=b+d*n; add(aa,turn(bb)); add(bb,turn(aa)); } } bool check() { for(int i=1;i<=n;i++) if(scc[i]==scc[i+n]) return false; return true; } void solve() { for(int i=1;i<=2*n;i++) { if(dfn[i]==0) { DFS(i); } } if(check())puts("YES"); else puts("NO"); } int main() { while(scanf("%d",&n)!=EOF) { scanf("%d",&m); init(); solve(); } return 0; } /* HDU 1824 */ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #include<map> #include<algorithm> using namespace std; const int MAXE=1000002; const int MAX=6009; struct EDGE { int v; // 从u点出发能到达的点v int next; // 从u点出发能到达的下一条边的编号 }edge[MAXE]; int first[MAX]; // first[u] = e:从点u出发的最后一条边的编号是e(“最后”是指最后输入) int dfn[MAX]; // dfn[u]:节点u搜索的次序编号(时间戳) int low[MAX];// low[u]:是u或u的子树能够追溯到的最早的栈中节点的次序号 int ins[MAX];// 是否在栈中 int scc[MAX]; // scc[i] = j:第i个点所在的强连通分量的编号 (此题可有可无) int t,n,m; int num; // 强连通分量的数目 int index; // 次序编号 int s[MAX]; int top,e; int a,b,c; int DFS(int x) { low[x]=dfn[x]=index++; s[++top]=x; ins[x]=1; // 枚举每一条边:u-->v for(int k=first[x];k!=-1;k=edge[k].next) { int v=edge[k].v; if(dfn[v]==0) { DFS(v); low[x]=min(low[x],low[v]); } else if(ins[v]) { low[x]=min(dfn[v],low[x]); } } // 如果节点u是强连通分量的根 if(low[x]==dfn[x]) { int v; num++; do{ v=s[top--]; ins[v]=0; scc[v]=num; }while(v!=x); } return 1; } inline void add(int u,int v) { edge[e].v=v; edge[e].next=first[u]; first[u]=e++; } void init() { memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(first,-1,sizeof(first)); // memset(ins,0,sizeof(ins)); index=1; top=-1; num=0; e=0; for(int i=1;i<=t;i++) { scanf("%d%d%d",&a,&b,&c); a++; b++; c++; add(a+n,b); add(a+n,c); add(b+n,a); add(c+n,a); } for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); a++; b++; add(a,b+n); add(b,a+n); } } bool check() { for(int i=1;i<=n;i++) if(scc[i]==scc[i+n]) return false; return true; } void solve() { for(int i=1;i<=2*n;i++) { if(dfn[i]==0) { DFS(i); } } if(check())puts("yes"); else puts("no"); } int main() { while(scanf("%d%d",&t,&m)!=EOF) { n=3*t; init(); solve(); } return 0; }