今天讲的是图论大体上分为:有向图的强连通分量,有向图的完全图:竞赛图,无向图的的割点,割边,点双联通分量,变双联通分量以及圆方树 2-sat问题 支配树等等。

大体上都知道是些什么东西 但是仍需要写一些东西来好好巩固一下基础。太菜了 加油!。

1 有向图的强联通分量 写过好多次了 判断条件为dfn[x]==low[x] 此时栈中的所有点形成一个强连通分量。

bzoj 最受欢迎的牛:

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=;
int n,m,len,cnt,top,num;
struct wy
{
int x,y;
}t[MAXN];
int c[MAXN],b[MAXN],out[MAXN];
int lin[MAXN],nex[MAXN],ver[MAXN];
int s[MAXN],dfn[MAXN],low[MAXN],vis[MAXN];
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline void dfs(int x)
{
dfn[x]=low[x]=++cnt;
s[++top]=x;vis[x]=;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!dfn[tn])
{
dfs(tn);
low[x]=min(low[x],low[tn]);
}
else if(vis[tn])low[x]=min(low[x],dfn[tn]);
}
//cout<<x<<' '<<dfn[x]<<' '<<low[x]<<endl;
if(dfn[x]==low[x])
{
int y;++num;
//cout<<x<<endl;
do
{
y=s[top--];
c[y]=num;++b[num];
vis[y]=;
}
while(y!=x);
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(int i=;i<=m;++i)
{
t[i].x=read();
t[i].y=read();
add(t[i].x,t[i].y);
}
for(int i=;i<=n;++i)if(!dfn[i])dfs(i);
//cout<<num<<endl;
for(int i=;i<=n;++i)
for(int j=lin[i];j;j=nex[j])
{
int tn=ver[j];
if(c[tn]==c[i])continue;
++out[c[i]];
}
int flag=;
for(int i=;i<=num;++i)
{
if(out[i]==&&flag)
{
puts("");
return ;
}
if(out[i]==&&flag==)flag=b[i];
}
printf("%d\n",flag);
return ;
}

杀人游戏:

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=;
int n,m,len,cnt,top,num,sum,flag,len1;
int lin[MAXN],ver[MAXN],nex[MAXN],out[MAXN];
int lin1[MAXN],ver1[MAXN],nex1[MAXN];
int vis[MAXN],s[MAXN];
int dfn[MAXN],low[MAXN],b[MAXN],c[MAXN],in[MAXN];
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline void add1(int x,int y)
{
ver1[++len1]=y;
nex1[len1]=lin1[x];
lin1[x]=len1;
}
inline void dfs(int x)
{
dfn[x]=low[x]=++cnt;
s[++top]=x;vis[x]=;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!dfn[tn])
{
dfs(tn);
low[x]=min(low[x],low[tn]);
}
else if(vis[tn])low[x]=min(low[x],dfn[tn]);
}
if(dfn[x]==low[x])
{
++num;int y;
do
{
y=s[top];--top;
c[y]=num;++b[num];
vis[y]=;
}
while(x!=y);
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(int i=;i<=m;++i)
{
int x,y;
x=read();y=read();
add(x,y);
}
for(int i=;i<=n;++i)if(!dfn[i])dfs(i);
//cout<<num<<endl;
for(int i=;i<=n;++i)
{
for(int j=lin[i];j;j=nex[j])
{
int tn=ver[j];
if(c[i]==c[tn])continue;
//cout<<c[tn]<<' '<<i<<endl;
add1(c[i],c[tn]);
++in[c[tn]];++out[c[i]];
}
}
for(int i=;i<=num;++i)
{
if(!in[i])++sum;
if(!in[i]&&!out[i]&&b[i]==)flag=;
if(!in[i]&&b[i]==)
{
int mark=;
for(int j=lin1[i];j;j=nex1[j])
{
int tn=ver1[j];
if(in[tn]==)mark=;
}
if(!mark)flag=;
}
}
printf("%.6lf\n",(n-sum+flag)*1.0/(n*1.0));
return ;
}

推荐一写 细节非常之多。

炸弹游戏 线段树优化建图+强连通分量。

线段树优化建图的话 我认为是 将一个点向一个区间整体连边 可转换成线段树上的连边 原因 我们不知道哪一条边起到了连接强连通分量的作用。

所以采用线段树优化一下边数至多为 2n+nlogn.

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 5000000000000000000ll
#define l(x) t[x].l
#define r(x) t[x].r
#define mn(x) t[x].mn
#define mx(x) t[x].mx
#define ll long long
#define mod 1000000007
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=;
int n,cnt,top,root,num,len,len1,T,h,w;
ll ans,vmn[MAXN<<],vmx[MAXN<<];
int ru[MAXN<<],q[MAXN<<];
int pos[MAXN],dfn[MAXN<<],low[MAXN<<],s[MAXN<<];
int vis[MAXN<<],c[MAXN<<];
int lin[MAXN<<],ver[MAXN*],nex[MAXN*];
int lin1[MAXN<<],ver1[MAXN*],nex1[MAXN*];
ll a[MAXN],b[MAXN];
struct wy//动态开点线段树 优化建图
{
int l,r;
ll mn,mx;
}t[MAXN<<];
inline void add(int x,int y)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;
}
inline void add1(int x,int y)
{
ver1[++len1]=y;nex1[len1]=lin1[x];lin1[x]=len1;
}
inline void tarjan(int x)
{
dfn[x]=low[x]=++w;
s[++top]=x;vis[x]=;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!dfn[tn])
{
tarjan(tn);
low[x]=min(low[x],low[tn]);
}
else if(vis[tn])low[x]=min(low[x],dfn[tn]);
}
if(dfn[x]==low[x])
{
++num;int y;
vmn[num]=INF;vmx[num]=-INF;
do
{
y=s[top--];
vis[y]=;c[y]=num;
vmn[num]=min(vmn[num],mn(y));
vmx[num]=max(vmx[num],mx(y));
}
while(x!=y);
}
}
inline void build(int &p,int l,int r)
{
if(!p)p=++cnt;
if(l==r)
{
pos[l]=p;
mn(p)=a[l];mx(p)=a[l];
return;
}
int mid=(l+r)>>;
build(l(p),l,mid);
build(r(p),mid+,r);
mn(p)=min(mn(l(p)),mn(r(p)));
mx(p)=max(mx(l(p)),mx(r(p)));
add(p,l(p));add(p,r(p));
}
inline void change(int p,int L,int R,int l,int r,int x)
{
if(L<=l&&R>=r)
{
add(x,p);
return;
}
int mid=(l+r)>>;
if(L<=mid)change(l(p),L,R,l,mid,x);
if(R>mid)change(r(p),L,R,mid+,r,x);
}
inline void topsort()
{
while(h++<T)
{
int x=q[h];
for(int i=lin1[x];i;i=nex1[i])
{
int tn=ver1[i];
--ru[tn];
vmn[tn]=min(vmn[tn],mn(x));
vmx[tn]=max(vmx[tn],mx(x));
if(!ru[tn])q[++T]=tn;
}
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();
for(int i=;i<=n;++i)a[i]=read(),b[i]=read();
build(root,,n);
for(int i=;i<=n;++i)
{
int l=lower_bound(a+,a++n,a[i]-b[i])-a;//这个一定不会越界
int r=upper_bound(a+,a++n,a[i]+b[i])-a-;//这个有可能会越界但是不会出错
//cout<<l<<' '<<r<<endl;
//cout<<pos[i]<<endl;
change(root,l,r,,n,pos[i]);
}
//cout<<cnt<<endl;
for(int i=;i<=cnt;++i)if(!dfn[i])tarjan(i);
//printf("%d\n",num);
//cout<<(ll)num<<endl;
for(int i=;i<=cnt;++i)
{
for(int j=lin[i];j;j=nex[j])
{
int tn=ver[j];
if(c[i]==c[tn])continue;
add1(c[tn],c[i]);++ru[c[i]];
}
}
for(int i=;i<=num;++i)if(!ru[i])q[++T]=c[i];
topsort();
for(int i=;i<=n;++i)
{
int l=lower_bound(a+,a++n,vmn[c[pos[i]]])-a;
int r=upper_bound(a+,a++n,vmx[c[pos[i]]])-a-;
ans+=(ll)(r-l+)*(ll)i%mod;
}
printf("%lld\n",ans%mod);
return ;
}

割点:BLO 以前的代码。

//#include<bits/stdc++.h>
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstdio>
#include<ctime>
#include<queue>
#include<stack>
#include<vector>
#include<cctype>
#include<utility>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<cstdlib>
#define INF 2147483646
#define ll long long
#define db double
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(ll x)
{
x<?putchar('-'),x=-x:;
ll num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const ll MAXN=;
ll n,m,num;
ll ans[MAXN],dfn[MAXN],low[MAXN],cut[MAXN];
ll sz[MAXN];//s[i]表示以i为根节点的子树大小
ll lin[MAXN<<],nex[MAXN<<],ver[MAXN<<],len;
inline void add(ll x,ll y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline ll min(ll x,ll y){return x>y?y:x;}
void tarjan(ll x)
{
dfn[x]=low[x]=++num;
sz[x]=;ll flag=,sum=;
for(ll i=lin[x];i;i=nex[i])
{
ll tn=ver[i];
if(!dfn[tn])
{
tarjan(tn);
sz[x]+=sz[tn];
low[x]=min(low[x],low[tn]);
if(low[tn]==dfn[x])
{
flag++;
if(x!=||flag>)
{
cut[x]=;sum+=sz[tn];
ans[x]+=sz[tn]*(n-sz[tn]-);
}
}
}
else low[x]=min(low[x],dfn[tn]);
}
if(cut[x])ans[x]+=(n-sum-)*sum;
return;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(ll i=;i<=m;++i)
{
ll x,y;
x=read();y=read();
add(x,y);add(y,x);
}
tarjan();
for(ll i=;i<=n;++i)put(ans[i]+(n-)*);
return ;
}

bzoj 3331 圆方树+树上差分 非常简单。

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 5000000000000000000ll
#define l(x) t[x].l
#define r(x) t[x].r
#define mn(x) t[x].mn
#define mx(x) t[x].mx
#define ll long long
#define mod 1000000007
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=,maxn=MAXN<<;
int n,m,k,len,top,num,cnt,T;
int dfn[MAXN],low[MAXN],s[MAXN];
int lin[maxn],ver[maxn],nex[maxn];
int f[MAXN<<][],d[MAXN<<],c[MAXN<<];
vector<int>g[MAXN];
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
void tarjan(int x)
{
low[x]=dfn[x]=++cnt;
s[++top]=x;
for(unsigned int i=;i<g[x].size();++i)
{
int tn=g[x][i];
if(!dfn[tn])
{
tarjan(tn);
low[x]=min(low[x],low[tn]);
if(dfn[x]==low[tn])
{
++num;
for(int j=;j!=tn;--top)
{
j=s[top];
add(num,j);
add(j,num);
}
add(num,x);
add(x,num);
}
}
else low[x]=min(low[x],dfn[tn]);
}
}
inline void dfs(int x,int father)
{
d[x]=d[father]+;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==father)continue;
f[tn][]=x;
for(int j=;j<=T;++j)f[tn][j]=f[f[tn][j-]][j-];
dfs(tn,x);
}
}
inline int LCA(int x,int y)
{
if(d[x]<d[y])swap(x,y);
for(int i=T;i>=;--i)
if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return x;
for(int i=T;i>=;--i)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][];
}
inline void dfs(int x)
{
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==f[x][])continue;
dfs(tn);
c[x]+=c[tn];
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();k=read();
for(int i=;i<=m;++i)
{
int x,y;
x=read();y=read();
g[x].push_back(y);
g[y].push_back(x);
}
num=n;tarjan();
//cout<<num<<endl;
T=(int)(log((n+num)*1.0)/log(2.0))+;
dfs(,);
//for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i),--top;
for(int i=;i<=k;++i)
{
int x,y;
x=read();y=read();
int lca=LCA(x,y);
++c[x];++c[y];
--c[lca];
if(f[lca][])--c[f[lca][]];
}
dfs();
for(int i=;i<=n;++i)printf("%d\n",c[i]);
return ;
}

luogu 4630 铁人两项

圆方树 + 特殊性质 +树形dp 想的还不是很成熟。

总之符合路径的一定是s 到 f 路径上的 圆点和方点 采用树形dp O(n)解决。

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 1000000000
#define ll long long
#define mod 1000000007
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=,maxn=MAXN<<;
int n,m,k,len,top,num,cnt,sz;
ll ans;
int dfn[MAXN],low[MAXN],s[MAXN],w[MAXN<<];
int lin[maxn],ver[maxn],nex[maxn],b[MAXN<<];
vector<int>g[MAXN];
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
void tarjan(int x)
{
low[x]=dfn[x]=++cnt;
s[++top]=x;++sz;
for(unsigned int i=;i<g[x].size();++i)
{
int tn=g[x][i];
if(!dfn[tn])
{
tarjan(tn);
low[x]=min(low[x],low[tn]);
if(dfn[x]==low[tn])
{
++num;
for(int j=;j!=tn;--top)
{
j=s[top];
add(num,j);
add(j,num);
++w[num];
}
add(num,x);
add(x,num);
++w[num];
}
}
else low[x]=min(low[x],dfn[tn]);
}
}
inline void dfs(int x,int father)
{
b[x]=x<=n;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==father)continue;
dfs(tn,x);
ans+=2ll*w[x]*b[x]*b[tn];
b[x]+=b[tn];
}
ans+=2ll*w[x]*b[x]*(sz-b[x]);
return;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(int i=;i<=n;++i)w[i]=-;
for(int i=;i<=m;++i)
{
int x,y;
x=read();y=read();
g[x].push_back(y);
g[y].push_back(x);
}
num=n;
for(int i=;i<=n;++i)
if(!dfn[i])
{
sz=;
tarjan(i);--top;
dfs(i,);
}
printf("%lld\n",ans);
return ;
}

luogu 3225 矿场搭建 
点双连通分量 其实也是割点的裸题 很有意思。

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define INF 2147483646
#define ll long long
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?putchar('-'),x=-x:;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=;
int n,len,num,root,c,cnt,sum,m,w;
ll ans;
int low[MAXN],dfn[MAXN],cut[MAXN],vis[MAXN];
int lin[MAXN<<],nex[MAXN<<],ver[MAXN<<];
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x>y?y:x;}
void tarjan(int x)
{
dfn[x]=low[x]=++num;
int flag=;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(dfn[tn]){low[x]=min(low[x],dfn[tn]);continue;}
else
{
tarjan(tn);
low[x]=min(low[x],low[tn]);
if(dfn[x]==low[tn])
{
++flag;
if(flag>||x!=root)cut[x]=;
}
}
}
}
void dfs(int x)
{
vis[x]=cnt;++sum;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(cut[tn]&&vis[tn]!=cnt)
{
vis[tn]=cnt;
++c;
}
if(!vis[tn]&&!cut[tn])dfs(tn);
}
}
int main()
{
//freopen("1.in","r",stdin);
for(int T=;;++T)
{
n=read();
if(!n)break;
memset(cut,,sizeof(cut));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(lin,,sizeof(lin));
memset(vis,,sizeof(vis));
len=;num=;cnt=;ans=;m=;w=;
for(int i=;i<=n;++i)
{
int x,y;
x=read();y=read();
m=max(m,max(x,y));
add(x,y);add(y,x);
}
for(int i=;i<=m;++i)if(!dfn[i])root=i,tarjan(i);
for(int i=;i<=m;++i)
{
if(vis[i]||cut[i])continue;
++cnt;sum=;c=;
dfs(i);
if(!c)ans=ans*(sum-)*sum/,w+=;
if(c==)ans*=sum,w+=;
if(c==);
}
printf("Case %d: %d %lld\n",T,w,ans);
}
return ;
}

bzoj 3495 2-sat模型 需要前缀和优化建图 很有意思。

//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 1000000000
#define ll long long
#define mod 1000000007
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=,maxn=MAXN<<;
int n,m,k,len,cnt,top,num,flag;
int c[MAXN<<];
int lin[maxn],ver[maxn],nex[maxn];
int s[MAXN<<],dfn[MAXN<<],low[MAXN<<],vis[MAXN<<];
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
s[++top]=x;vis[x]=;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!dfn[tn])
{
tarjan(tn);
low[x]=min(low[x],low[tn]);
}
else if(vis[tn])low[x]=min(low[x],dfn[tn]);
}
if(dfn[x]==low[x])
{
++num;int y;
do
{
y=s[top--];
vis[y]=;c[y]=num;
}
while(x!=y);
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();k=read();
for(int i=;i<=m;++i)
{
int x,y;
x=read();y=read();//x选 x+n不选
add(x+n,y);add(y+n,x);
}
for(int i=;i<=k;++i)
{
int w;
w=read();
for(int j=;j<=w;++j)s[j]=read();
for(int j=;j<=w;++j)add(s[j]+*n,s[j-]+*n);//前缀和
for(int j=w-;j>=;--j)add(s[j]+*n,s[j+]+*n);//后缀和
for(int j=;j<=w;++j)
{
if(j>)add(s[j],s[j-]+*n);
if(j<w)add(s[j],s[j+]+*n);
}
}
for(int i=;i<=n;++i)add(i+*n,i+n),add(i+*n,i+n);
for(int i=;i<=*n;++i)if(!dfn[i])tarjan(i);
for(int i=;i<=n;++i)if(c[i]==c[i+n])flag=;
if(flag)puts("NIE");else puts("TAK");
return ;
}

2019 HL SC day1的更多相关文章

  1. 2019 HL SC day10

    10天都过去了 4天都在全程懵逼.. 怎么可以这么难啊 我服了 现在想起依稀只记得一些结论 什么 反演? 什么后缀自动机?什么组合数的应用?什么神仙东西 ,不过讲课人的确都是神仙.(实名羡慕. mzx ...

  2. 2019 HL SC day4

    自闭场本来 以为 顶多一些不太会 结果发现 一堆不太会 . 树状数组  感觉 好久没看 了有点遗忘 不过还好 现在我来了.莅临之神将会消灭一切知识点哦. 今天说点不一样东西 树状数组 hh 很有用的东 ...

  3. 2019 HL SC day2

    今天讲的是网络流 大部分题目都写过了 这里 就总结一番. bzoj 1066 裸的最大流 不过需要拆点细节方面有一点坑 剩下的 没什么了. //#include<bits/stdc++.h> ...

  4. Solr分组查询

     项目中需要实时的返回一下统计的东西,因此就要进行分组,在获取一些东西,代码拿不出来,因此分享一篇,还是很使用的. facet搜索 /** * * 搜索功能优化-关键词搜索 * 搜索范围:商品名称.店 ...

  5. Light of future-冲刺集合

    table th:nth-of-type(1) { width: 85px; } table th:nth-of-type(2){ width: 80px; } table th:nth-of-typ ...

  6. Light of future-冲刺总结

    目录 1.凡事预则立.测试博客的链接 2.包含冲刺日志集合随笔的所有内容 3.描述项目预期计划 7.代码仓库地址.测试文档链接地址.PPT链接地址 归属班级 →2019秋福大软件工程实践Z班 作业要求 ...

  7. Python3的日期和时间

    2019独角兽企业重金招聘Python工程师标准>>> python 中处理日期时间数据通常使用datetime和time库 因为这两个库中的一些功能有些重复,所以,首先我们来比较一 ...

  8. 【LOJ】#3032. 「JOISC 2019 Day1」馕

    LOJ#3032. 「JOISC 2019 Day1」馕 处理出每个人把馕切成N段,每一段快乐度相同,我们选择第一个排在最前的人分给他的第一段,然后再在未选取的的人中选一个第二个排在最前的切一下,并把 ...

  9. 【LOJ】#3031. 「JOISC 2019 Day1」聚会

    LOJ#3031. 「JOISC 2019 Day1」聚会 听说随机可过? 我想了很久想了一个不会被卡的做法,建出前\(u - 1\)个点的虚树,然后找第\(u\)个点的插入位置,就是每次找一条最长链 ...

随机推荐

  1. 大厂前端带来css3动画transition的使用和介绍全新认识动画

    CSS3中可以使用transition来做最简单动画效果,transition表示到一个元素的属性值发生变化时,我们可以看到页面元素从旧的属性慢慢变化为新的属性值的过程,这种效果不是立即变化的,而是体 ...

  2. 面试必杀技,讲一讲Spring中的循环依赖

    本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configu ...

  3. 读CSAPP第二章的收获

    一:一道很有意思的位运算题目:你只有两种操作 bis(x, y): 在y为1的每个位置上,将x的对应的位设为1bic(x, y): 在y为1的每个位置上,将x的对应的位设为0 简单的化简一下bis(x ...

  4. Java入门基础学习,成为一个Java程序员的必备知识

    引言 众所周知,Java是一种面向对象的编程语言.您可以在Windows操作系统上编写Java源代码,而在Linux操作系统上运行编译后的字节码,而无需修改源代码. 数据类型 Java 有 2 种数据 ...

  5. nginx限制访问域名,禁止IP访问

    有些时候我们希望系统只能通过固定的域名访问,禁止IP或者恶意绑定的域名访问. 下面的nginx配置,假如host变量不是指定的域名,将返回403. server { listen 80; server ...

  6. [BSidesCF 2020]Had a bad day

    [BSidesCF 2020]Had a bad day 测试 一些猫狗的图片加上url有传参,测试到文件包含时报错了. 使用php伪协议: php伪协议 php://fliter/read=conv ...

  7. python 面试题一:Python语言特性

    1 Python的函数参数传递 两个例子 a = 1 def fun(a): a = 2 fun(a) print a # a = [] def fun(a): a.append(1) fun(a) ...

  8. sublime text 3+java只编译不输出结果 solution

    文章摘自:https://blog.csdn.net/VincentLuo91/article/details/53007135 版权声明:本文为CSDN博主「vincentluo91」的原创文章,遵 ...

  9. .NET Core 跨平台

    前言   .NET Core是一个开源的模块化的Framework,不管是开发web或移动设备都在同一个Framework(.NET Core)下运行,而且 .NET Core也可在不同的操作系统上运 ...

  10. Android 性能优化 ---- 启动优化

    Android 性能优化 ---- 启动优化 1.为什么要进行启动优化 一款应用的第一印象很重要,第一印象往往决定了用户的去留.打开一款应用,如果速度很快,很顺畅,那么很容易让人觉得这款应用背后的技术 ...