1263D - Secret Passwords
如果该字符串没有被标记就去遍历他的每一个字母,通过该字母去感染别的字符串,当然别的字符串中的字母也会被该字母感染,最后看看cnt是多少就可以
#include <bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll mod=10007;
ll n,vis[30],vv[200005];
string s[200005];
vector<ll>v[30];
ll cnt;
void dfs(ll u,ll ind){
//cout<<u<<" "<<vis[u];
for(int i=0;i<v[u].size();i++){
ll x=v[u][i];
if(vv[x]) continue;
vv[x]=vv[ind];
//cout<<x<<" "<<u<<" "<<vv[x]<<" "<<vv[u]<<endl;
for(int j=0;j<s[x].size();j++){
if(vis[s[x][j]-'a']) continue;
vis[s[x][j]-'a']=vis[u];
//cout<<u<<" "<<s[x][j]<<" "<<vis[u]<<endl;
dfs(s[x][j]-'a',x);
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i];
for(int j=0;j<s[i].size();j++)
v[s[i][j]-'a'].push_back(i);
}
cnt=0;
for(int i=1;i<=n;i++){
if(vv[i]) continue;
cnt++;
vv[i]=cnt;
for(int j=0;j<s[i].size();j++){
if(vis[s[i][j]-'a']) continue;
vis[s[i][j]-'a']=cnt;
dfs(s[i][j]-'a',i);
}
}
printf("%lld\n",cnt);
system("pause");
return 0;
}
G-Link with Monotonic Subsequence_"蔚来杯"构造
自己的代码写的好丑,实现的方法也不是很对,最关键的地方是每组分成sqrt(n)向上取整个,然后倒着输出就可以,被签到卡住了,不愧是我
#include <bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll mod=10007;
ll t,n;
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld",&n);
ll m=ceil(sqrt(n));
ll k=n%m;
for(int i=k;i>=1;i--) printf("%d ",i);
for(int i=k;i<n;i+=m)
for(int j=i+m;j>i;j--) printf("%d ",j);
printf("\n");
}
system("pause");
return 0;
}
P1967 [NOIP2013 提高组] 货车运输 - 洛谷 重构树
重构树的模板,可以处理从点x到点y所有路径上最大边权的最小值或者最小边权的最大值;丫的我用前向星MLE,用vector就不MLE,淦
Kruskal重构树——学习笔记_linbinwu123的博客-CSDN博客_kruskal重构树
#include <bits/stdc++.h>
#define ll int
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll mod=10007;
ll n,m,s[20005],val[20005];
ll siz[20005],d[20005],f[20005],top[20005],son[20005];
vector<int> g[20005];
void dfs1(ll u,ll fa){
siz[u] =1;f[u]=fa;d[u]=d[fa]+1;son[u]=0;
for(int i=0;i<g[u].size();i++){
ll j=g[u][i];
if(j==fa) continue;
dfs1(j,u);
siz[u]+=siz[j];
if(siz[son[u]]<siz[j]) son[u]=j;
}
}
void dfs2(ll u,ll topx){
top[u]=topx;
if(son[u]) dfs2(son[u],topx);
for(int i=0;i<g[u].size();i++){
if(g[u][i]!=f[u]&&g[u][i]!=son[u])
dfs2(g[u][i],g[u][i]);
}
}
ll lca(ll x,ll y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
x=f[top[x]];
}
return d[x]<d[y] ? x : y;
}
struct node{
ll u,v,w;
bool operator<(const node& a)const { return w>a.w; }
//升序为(u, v)间多条路中最大边权最小值
//降序为(u, v)间多条路中最小边权最大值
}ed[50005];
ll findd(ll x){return x==s[x]?x:s[x]=findd(s[x]);}
void exkruscal(){
ll ct=n;
for(int i=1;i<=(n<<1);i++) s[i]=i,val[i]=-1;
sort(ed+1,ed+m+1);
for(int i=1;i<=m;i++){
ll xx=findd(ed[i].u),yy=findd(ed[i].v);
if(xx==yy) continue;
val[++ct]=ed[i].w;
s[xx]=s[yy]=ct;
g[xx].push_back(ct), g[ct].push_back(xx);
g[yy].push_back(ct), g[ct].push_back(yy);
if(ct>=(n<<1)-1) break;
}
for(int i=1;i<=ct;i++){
if(!siz[i]){
ll xx=findd(i);
dfs1(xx,0);dfs2(xx,xx);
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
}
exkruscal();
ll q; scanf("%d",&q);
while(q--){
ll u,v;
scanf("%d%d",&u,&v);
if(findd(u)!=findd(v)) printf("-1\n");
else printf("%d\n",val[lca(u,v)]);
}
system("pause");
return 0;
}
P2245 星际导航 - 洛谷 | 重构树
这个题算是双倍经验了吧,上一个题是最大边权的最小值,这个题是最小边权的最大值
#include <bits/stdc++.h>
#define ll int
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll mod=10007;
ll n,m,s[200005],val[200005];
ll siz[200005],d[200005],f[200005],top[200005],son[200005];
vector<int> g[200005];
ll head[50005],cnt;
struct Edge{
ll from,to,next,w;
}edge[50005];
void addedge(ll from, ll to){
edge[++cnt].from = from;
edge[cnt].to = to;
edge[cnt].next = head[from];
head[from] = cnt;
}
void dfs1(ll u,ll fa){
siz[u] =1;f[u]=fa;d[u]=d[fa]+1;son[u]=0;
for(int i=0;i<g[u].size();i++){
ll j=g[u][i];
if(j==fa) continue;
dfs1(j,u);
siz[u]+=siz[j];
if(siz[son[u]]<siz[j]) son[u]=j;
}
}
void dfs2(ll u,ll topx){
top[u]=topx;
if(son[u]) dfs2(son[u],topx);
for(int i=0;i<g[u].size();i++){
if(g[u][i]!=f[u]&&g[u][i]!=son[u])
dfs2(g[u][i],g[u][i]);
}
}
ll lca(ll x,ll y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
x=f[top[x]];
}
return d[x]<d[y] ? x : y;
}
struct node{
ll u,v,w;
bool operator<(const node& a)const { return w<a.w; }
//升序为(u, v)间多条路中最大边权最小值
//降序为(u, v)间多条路中最小边权最大值
}ed[300005];
ll findd(ll x){return x==s[x]?x:s[x]=findd(s[x]);}
void exkruscal(){
ll ct=n;
for(int i=1;i<=(n<<1);i++) s[i]=i,val[i]=-1;
sort(ed+1,ed+m+1);
for(int i=1;i<=m;i++){
ll xx=findd(ed[i].u),yy=findd(ed[i].v);
if(xx==yy) continue;
val[++ct]=ed[i].w;
s[xx]=s[yy]=ct;
g[xx].push_back(ct), g[ct].push_back(xx);
g[yy].push_back(ct), g[ct].push_back(yy);
if(ct>=(n<<1)-1) break;
}
for(int i=1;i<=ct;i++){
if(!siz[i]){
ll xx=findd(i);
dfs1(xx,0);dfs2(xx,xx);
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
}
exkruscal();
ll q; scanf("%d",&q);
while(q--){
ll u,v;
scanf("%d%d",&u,&v);
if(findd(u)!=findd(v)) printf("impossible\n");
else printf("%d\n",val[lca(u,v)]);
}
system("pause");
return 0;
}
E-水灾_牛客练习赛62 重构树
又是莫名其妙的MLE,这次用前向星才过的,,,好像改了下数组大小就过了,,,
所选的点中,任意两点的最小路径要大于x才不会断开,所以也就是任意两点路径中的最小权值的最大值要小于等于x,这也说明了重构树是一个小根堆,小根堆相隔的越远val值也就越小,所以不用两两求lca会超时,直接算相邻的就可以,用dfn数组记录dfs序,注意d数组不能用来排序,因为也算入边权转化成的点了,虽然不是很懂为啥是要dfs序,但是经过手推之后发现dfs序是对的,应该是和排序和建树的顺序是有关的,但是没想出来原理到底是啥,可能是脑子已经不转了,,,
现在是2022/7/25,再来看一下,如图
用它来建一个小根堆的重构树,按照这样的输入顺序
就会得到如下图的重构树
dfs序是9,5,8,7,6,4,2,3,1,发现除了5,4外都是相邻的,而且5,4也可以看成是某种意义上的相邻,所以dfs序求相邻是正确的
Kruskal重构树——学习笔记_linbinwu123的博客-CSDN博客_kruskal重构树
#include <bits/stdc++.h>
#define ll int
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll MAX=1e6+5;
const ll mod=10007;
ll n,m,q,s[MAX],val[MAX];
ll siz[MAX],d[MAX],dfnt,dfn[MAX],f[MAX],top[MAX],son[MAX];
ll head[MAX],cnt;
struct Edge{
ll from,to,next,w;
}edge[MAX<<1];
void addedge(ll from, ll to){
edge[++cnt].from = from;
edge[cnt].to = to;
edge[cnt].next = head[from];
head[from] = cnt;
}
void dfs1(ll u,ll fa){
dfn[u]=++dfnt;
siz[u] =1;f[u]=fa;d[u]=d[fa]+1;son[u]=0;
for(int i=head[u];i;i=edge[i].next){
ll j=edge[i].to;
if(j==fa) continue;
dfs1(j,u);
siz[u]+=siz[j];
if(siz[son[u]]<siz[j]) son[u]=j;
}
}
void dfs2(ll u,ll topx){
top[u]=topx;
if(son[u]) dfs2(son[u],topx);
for(int i=head[u];i;i=edge[i].next){
if(edge[i].to!=f[u]&&edge[i].to!=son[u])
dfs2(edge[i].to,edge[i].to);
}
}
ll lca(ll x,ll y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
x=f[top[x]];
}
return d[x]<d[y] ? x : y;
}
struct node{
ll u,v,w;
bool operator<(const node& a)const { return w>a.w; }
//升序为(u, v)间多条路中最大边权最小值
//降序为(u, v)间多条路中最小边权最大值
}ed[MAX];
ll findd(ll x){return x==s[x]?x:s[x]=findd(s[x]);}
void exkruscal(){
ll ct=n;
for(int i=1;i<=(n<<1);i++) s[i]=i,val[i]=-1;
sort(ed+1,ed+m+1);
for(int i=1;i<=m;i++){
ll xx=findd(ed[i].u),yy=findd(ed[i].v);
if(xx==yy) continue;
val[++ct]=ed[i].w;
s[xx]=s[yy]=ct;
addedge(ct,xx);addedge(xx,ct);
addedge(ct,yy);addedge(yy,ct);
if(ct>=(n<<1)-1) break;
}
for(int i=1;i<=ct;i++){
if(!siz[i]){
ll xx=findd(i);
dfs1(xx,0);dfs2(xx,xx);
}
}
}
bool cmp(ll a,ll b){
return dfn[a]<dfn[b];
//return d[a]<d[b];
}
ll a[MAX];
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
}
exkruscal();
ll last=0,k;
//for(int i=1;i<=2*n;i++) cout<<d[i]<<" "<<dfn[i]<<" "<<findd(i)<<endl;;cout<<endl;
while(q--){
scanf("%d",&k);
for(int i=1;i<=k;i++) scanf("%d",&a[i]),a[i]^=last;
sort(a+1,a+k+1,cmp);
for(int i=1;i<=k;i++) cout<<i<<" "<<a[i]<<" "<<dfn[a[i]]<<" "<<d[a[i]]<<" cao"<<endl;
ll ans=0;
for(int i=2;i<=k;i++){
ans=max(ans,val[lca(a[i],a[i-1])]);
cout<<val[lca(a[i],a[i-1])]<<" cc "<<a[i]<<" "<<a[i-1]<<endl;
}
printf("%d\n",ans);last=ans;
}
system("pause");
return 0;
}