hdu1232:http://acm.hdu.edu.cn/showproblem.php?pid=1232
代码:
#include
#define MAXN 100005
int f[MAXN];
void init()
{
for(int i=0;i
CodeForces - 977E:https://vjudge.net/problem/CodeForces-977E
题意:
给你一个图,问你有几个没有杂边的单环(度全为2)
解析:
度为1的点不用管,连续边,判断是否连通,如果连通,ans++,否则连接这个边
ac:
#include
#define MAXN 400005
using namespace std;
int f[MAXN];
int in[MAXN];
int ans=0;
void init()
{
for(int i=0;i
hdu1272:https://vjudge.net/problem/HDU-1272
题意:判断是否连通且无环
代码:
#include
#define MAXN 1000005
using namespace std;
int vis[MAXN];
int f[MAXN],sign;
int n,m,k,maxs;
void init()
{
maxs=sign=k=0;
memset(vis,0,sizeof(vis));
for(int i=1;i1)
sign=1;
if(!sign)
printf("Yes\n");
else
printf("No\n");
init();
}
else{
maxs=max(maxs,max(n,m));
unite(n,m);
vis[n]=vis[m]=1; ///标记
}
}
return 0;
}
https://pintia.cn/problem-sets/994805046380707840/problems/994805063963230208
题意:
按顺序失去城市,判断对图的连通性的改变
解析:
如果破坏连通性,首先呢个城市集合独立,还会造成另外的集合分开
如果只是不同集合数+1,呢是有个点与它原来集合分开
如果不改变集合数,呢是呢个点是孤立点
暴力模拟所以情况
ac:
#include
#define MAXN 10005
using namespace std;
int a[MAXN],b[MAXN];
int f[MAXN];
int vis[MAXN];
void init()
{
for(int i=0;i
https://ac.nowcoder.com/acm/contest/1080/B
题意:
用并查集模拟链表
#include
#define MAXN 2000005
using namespace std;
int a[MAXN];
int f[MAXN];
int c[MAXN];
void init(int n)
{
for(int i=0;i<=n;i++)
f[i]=i;
}
int get(int x)
{
if(x!=f[x])
f[x]=get(f[x]);
return f[x];
}
void unite(int a,int b)
{
f[get(a)]=get(b);
}
int main()
{
int n;
scanf("%d",&n);
init(n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
int x=a[i]%n;
if(c[x]==0)
c[x]=i;
else{
while(c[x]!=0)
{
if(x+1
或者用set也可以做:
#include
using namespace std;
typedef long long ll;
const ll MOD=998244353;
const int maxn=1e6+10;
int ma[maxn];
sets;
int main()
{
s.clear();
int n;
scanf("%d",&n);
for(int i=0;i::iterator it;
it=s.lower_bound(x);
if(it!=s.end()){
k=*it;
s.erase(it);
}
else{
it=s.begin();
k=*it;
s.erase(it);
}
ma[k]=ans;
}
for(int i=0;i
http://codeforces.com/contest/1139/problem/C
题意:
给定n-1条边一棵树(无环图),一个k,一些边是红边,一些是黑边
问有多少个种路径(路径上有k个点)是会过红边的?
解析:
总共有n^k种情况,减到只过黑边的就是答案
用并查集判断连通,找每个连通快内的连通点数目x
ans=n^k-(x(1)^k+x(2)^k+...x(n)^k)
含n个元素的集合选取k个元素有n^k种
ac:
#include
#define ll long long
#define mod 1000000007
#define MAXN 2000005
using namespace std;
vector vc[MAXN];
int f[MAXN];
int bb[MAXN];
int vis[MAXN];
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
void init()
{
for(int i=0;i
http://codeforces.com/contest/1213/problem/G
题意:
给定一棵树,树边有边权,然后按顺序删除删除一些边,问你这棵树上不含这些边的二元组个数
解析:
离线按边权从小到大加入边,然后判断连通块的个数
用并查集判连通,每个连通块的贡献是:sz*(sz-1)/2.
解析:
#include
#define MAXN 200005
#define ll long long
using namespace std;
struct node
{
ll u,v,w;
friend bool operator <(node a,node b)
{
return a.wval[y])
swap(x,y);
val[y]+=val[x];
f[x]=y;
}
ll ans[MAXN]={0};
int main()
{
init();
ll n,m,x;
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n-1;i++)
scanf("%lld%lld%lld",&ee[i].u,&ee[i].v,&ee[i].w);
sort(ee+1,ee+n-1+1);
ll st=0,ed=0;
for(ll i=1;i<=n-1;)
{
ll k=ee[i].w;
while(i<=n-1&&ee[i].w==k)
{
unite(ee[i].u,ee[i].v);
i++;
}
for(ll i=st;i
并查集还用在缩点中,根据题目意思把相同性质的元素,归属同一集合,将他们视作同一类东西
D. Gourmet choice
链接:D - Gourmet choice
题意:
给两个数组,长度分别为n,m.给两个数组的关系
构造出最小的两个数组,如果无法构造,输出NO,否则YES,输出两个数组
解析:
并查集(缩点)+拓扑排序
首先要判断是否有环,有环NO
对与"=",我们把它合成一个点,用并查集
用拓扑排序判断是否有环和构造数组
ac:
#include
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define IO ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define ll long long
#define MAXN 5005
using namespace std;
char str[1010][1010]={0};
int f[MAXN];
int in[MAXN]={0};
vector mp[MAXN];
int reward[MAXN]={0};
int n,m;
void init(){
rep(i,1,MAXN)
f[i]=i;
}
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
void unite(ll a,ll b){
ll x=find(a),y=find(b);f[x]=y;
}
void topo()
{
queue que;
for(int i=1;i<=n+m;i++)
if(in[i]==0)
{
reward[i]=1;
que.push(i);
}
int count=0;
while(!que.empty())
{
int top=que.front();
que.pop();
count++;
for(int i=0;i')
{
mp[find(n+j)].push_back(find(i));
in[find(i)]++;
}
else {
mp[find(i)].push_back(find(n+j));
in[find(n+j)]++;
}
}
topo();
return 0;
}
题目链接:http://lx.lanqiao.org/problem.page?gpid=T114
问题描述
C国由n个小岛组成,为了方便小岛之间联络,C国在小岛间建立了m座大桥,每座大桥连接两座小岛。两个小岛间可能存在多座桥连接。然而,由于海水冲刷,有一些大桥面临着不能使用的危险。
如果两个小岛间的所有大桥都不能使用,则这两座小岛就不能直接到达了。然而,只要这两座小岛的居民能通过其他的桥或者其他的小岛互相到达,他们就会安然无事。但是,如果前一天两个小岛之间还有方法可以到达,后一天却不能到达了,居民们就会一起抗议。
现在C国的国王已经知道了每座桥能使用的天数,超过这个天数就不能使用了。现在他想知道居民们会有多少天进行抗议。
输入格式:
输入的第一行包含两个整数n, m,分别表示小岛的个数和桥的数量。
接下来m行,每行三个整数a, b, t,分别表示该座桥连接a号和b号两个小岛,能使用t天。小岛的编号从1开始递增。
输出格式:
输出一个整数,表示居民们会抗议的天数。
解析:
前一天可以到达,后一天无法到达,判连通
我们逆着建图,时间从大到小排序
合并,如果不连通sum++(且这天没有被标记),并且标记这一天
ac:
#include
#define MAXN 100005
using namespace std;
int n,m;
int a,b,t,sum;
struct node
{
int a,b,t;
}q[MAXN];
int f[MAXN];
int vis[MAXN];
int cmp(node x,node y)
{
return x.t>y.t;
}
int find(int x)
{
if(f[x] != x)
f[x]=find1(f[x]);
return f[x];
}
int unite(int x,int y)
{
int fx = find1(x),fy = find1(y);
if(fx != fy)
{
f[fx] = fy;
return 0;
}
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
sum=0;
for(int i=1;i<=MAXN;i++)
{
f[i]=i;
vis[i]=0;
}
for(int i=1;i<=m;i++)
scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].t);
sort(q+1,q+m+1,cmp);
for(int i=1;i<=m;i++)
{
int w=mix(q[i].a,q[i].b);
if(w==0&&vis[q[i].t]==0)
{
sum++;
vis[q[i].t]=1;
}
}
printf("%d\n",sum);
return 0;
}
题目地址:https://nanti.jisuanke.com/t/41384n
题意:
给定一个n,q次操作,每次操作有两种情况:(1,x)或者(2,x)(1<=x<=n<=1e9)
1 x,将x删除
2 x,输出大于等于x,并且存在的数
解析:
离散化的并查集
开始用unordered_map超时了,查询太多了,unordered_map也不是万能的
ac:
#include
#define MAXN 2000005
#define ll long long
using namespace std;
int b[MAXN];
int f[MAXN];
int get(int x)
{
if(f[x]!=x)
f[x]=get(f[x]);
return f[x];
}
void init()
{
for(int i=0;i