木柜子组乐队
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int a,b,c,d,e;
cin>>a>>b>>c>>d>>e;
cout<<a*b*c*(d*(d-1)/2)+a*b*c*d*e<<"\n";
}
return 0;
}
森林迷宫
a[u].emplace_back(v,w);
a[v].emplace_back(u,w);
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef tuple<int,int,int> edge;
vector<edge>a[100005];
int d[100005],fa[100005],f[100005];
bool vis[100005];
void dfs(int u)
{
for(auto [v,w,c]:a[u])
{
if(v!=fa[u])
{
d[v]=d[u]+w;
fa[v]=u;
dfs(v);
}
}
}
void dp(int u)
{
f[u]=0;
for(auto [v,w,c]:a[u])
{
if(!vis[v]&&v!=fa[u])
{
dp(v);
if(f[v]+c>0)
{
f[u]=f[u]+f[v]+c;
}
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
a[i].clear();
vis[i]=false;
}
for(int i=1;i<n;i++)
{
int u,v,p,q;
cin>>u>>v>>p>>q;
a[u].emplace_back(v,p,p+q);
a[v].emplace_back(u,q,q+p);
}
int s,t;
cin>>s>>t;
d[s]=fa[s]=0;
dfs(s);
int ans=d[t];
vector<int>path;
while(t!=s)
{
path.push_back(t);
vis[t]=true;
t=fa[t];
}
path.push_back(s);
vis[s]=true;
reverse(path.begin(),path.end());
for(int x:path)
{
dp(x);
ans+=f[x];
}
cout<<ans<<"\n";
}
return 0;
}
最早连续串
- 分别维护0和1就好了。你不应该拖到三个半小时的时候才过掉这题的
#include <bits/stdc++.h>
using namespace std;
int a[500005];
struct t1
{
int l,r,bj;
int lc[2],rc[2],maxc[2];
#define len(x) t[x].r-t[x].l+1
}t[2000005];
void build(int p,int l,int r)
{
t[p].l=l;
t[p].r=r;
t[p].bj=-1;
if(l==r)
{
t[p].lc[a[l]]=t[p].rc[a[l]]=t[p].maxc[a[l]]=1;
t[p].lc[a[l]^1]=t[p].rc[a[l]^1]=t[p].maxc[a[l]^1]=0;
return;
}
int mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
for(int i=0;i<2;i++)
{
t[p].lc[i]=t[p*2].lc[i]+(t[p*2].lc[i]==len(p*2))*t[p*2+1].lc[i];
t[p].rc[i]=t[p*2+1].rc[i]+(t[p*2+1].rc[i]==len(p*2+1))*t[p*2].rc[i];
t[p].maxc[i]=max({t[p*2].maxc[i],t[p*2+1].maxc[i],t[p*2].rc[i]+t[p*2+1].lc[i]});
}
}
void cl(int p,int v)
{
t[p].lc[v]=len(p);
t[p].rc[v]=len(p);
t[p].maxc[v]=len(p);
t[p].lc[v^1]=0;
t[p].rc[v^1]=0;
t[p].maxc[v^1]=0;
}
void spread(int p)
{
if(t[p].bj!=-1)
{
int x=t[p].bj;
t[p*2].bj=t[p].bj;
t[p*2+1].bj=t[p].bj;
cl(p*2,x);
cl(p*2+1,x);
t[p].bj=-1;
}
}
void change(int p,int l,int r,int v)
{
if(l<=t[p].l&&r>=t[p].r)
{
cl(p,v);
t[p].bj=v;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)
{
change(p*2,l,r,v);
}
if(r>mid)
{
change(p*2+1,l,r,v);
}
for(int i=0;i<2;i++)
{
t[p].lc[i]=t[p*2].lc[i]+(t[p*2].lc[i]==len(p*2))*t[p*2+1].lc[i];
t[p].rc[i]=t[p*2+1].rc[i]+(t[p*2+1].rc[i]==len(p*2+1))*t[p*2].rc[i];
t[p].maxc[i]=max({t[p*2].maxc[i],t[p*2+1].maxc[i],t[p*2].rc[i]+t[p*2+1].lc[i]});
}
}
int ask(int p,int x,int k)
{
if(t[p].l==t[p].r)
{
return t[p].l;
}
spread(p);
if(t[p*2].maxc[x]>=k)
{
return ask(p*2,x,k);
}
else if(t[p*2].rc[x]+t[p*2+1].lc[x]>=k)
{
return ((t[p].l+t[p].r)>>1)-t[p*2].rc[x]+1;
}
else
{
return ask(p*2+1,x,k);
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
string s;
cin>>s;
for(int i=0;i<s.size();i++)
{
a[i+1]=s[i]-'0';
}
build(1,1,s.size());
int q;
cin>>q;
while(q--)
{
int op,k;
cin>>op>>k;
if(t[1].maxc[op]<k)
{
cout<<"-1\n";
}
else
{
int p=ask(1,op,k);
cout<<p<<"\n";
change(1,p,p+k-1,op^1);
}
}
}
return 0;
}
未来城市
- 对费用流有了更深刻的理解:如果原图不存在负圈,SSP算法可以保证迭代过程中的新图也不会出现负圈,但是如果你要手动跑费用流,那得到的图有没有负圈就不一定了
- 网络流算法的确可以更快地解决二分图最大匹配问题,但此时得到的解就不受你的控制了
- 本题的关键点在于要想到在\(a_i\)和\(b_i\)之间连边,同一个连通块内的点之间都可以相互替代
- 同样试图用二分图最大匹配“乱搞”,你看别人就能想到限制每个点至多访问100次,你就没能想到
- 等一下,突然发现你电脑上存储的最后一个版本提交是能通过的???只是赛场上你自己都不相信能过所以干脆都没交???
- 大概是这一行“乱搞”代码真的起了作用,不知道该说什么好……:
if(ma[a[i][0]]&&ma[a[i][1]]&&ma[a[i][0]]<ma[a[i][1]])
{
swap(a[i][0],a[i][1]);
}
- 遇到挫折难免影响情绪。在正式比赛的时候,你可以通过考前提醒设想此类情况,来让自己更快地接受现状,保持理智之心;但平时训练你难免产生情绪波澜,这个时候不妨强制自己趴下来休息一会儿,洗净过去的不愉快之后,再以崭新的面貌面对新的挑战
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed a[200005][2];
signed ma[200005];
bool v[200005],e[200005];
signed q[200005],tot;
bool dfs(int n1)
{
v[n1]=true;
q[++tot]=n1;
for(int i=0;i<2;i++)
{
if(!ma[a[n1][i]]||v[ma[a[n1][i]]]==false&&e[ma[a[n1][i]]]==true&&dfs(ma[a[n1][i]]))
{
ma[a[n1][i]]=n1;
return true;
}
}
return e[n1]=false;
}
struct g1
{
signed u,v,w;
}g[200005];
bool cmp(g1 a,g1 b)
{
return a.w>b.w;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
memset(ma,0,sizeof(ma[0])*(n+1));
for(int i=1;i<=m;i++)
{
cin>>g[i].u>>g[i].v>>g[i].w;
}
sort(g+1,g+m+1,cmp);
for(int i=1;i<=m;i++)
{
e[i]=true;
a[i][0]=g[i].u;
a[i][1]=g[i].v;
}
int ans=0;
for(int i=1;i<=m;i++)
{
tot=0;
if(ma[a[i][0]]&&ma[a[i][1]]&&ma[a[i][0]]<ma[a[i][1]])
{
swap(a[i][0],a[i][1]);
}
ans+=dfs(i)*g[i].w;
for(int j=1;j<=tot;j++)
{
v[q[j]]=false;
}
}
cout<<ans<<"\n";
}
return 0;
}
随机游走
- 边双连通分量内的点(点数大于一),以及任意两个边双连通分量之间的点(树上统计),一定可以被纳入答案
- 在剩下的树中,以边双为根,寻找\(u \rightarrow lca \rightarrow root \rightarrow lca \rightarrow v\)式的路径
#include <bits/stdc++.h>
#define int long long
using namespace std;
vector<int>a[200005];
vector<int>c[200005];
int fa[200005],dfn[200005],low[200005],h[200005],to[400005],nx[400005],tot,ans;
bool cut[400005],vis[200005];
int w[200005],d[200005];
void add(int u,int v)
{
tot++;
cut[tot]=false;
to[tot]=v;
nx[tot]=h[u];
h[u]=tot;
}
int get(int x)
{
if(fa[x]==x)
{
return x;
}
return fa[x]=get(fa[x]);
}
void tarjan(int u,int fa)
{
dfn[u]=low[u]=++tot;
for(int i=h[u];i;i=nx[i])
{
int v=to[i];
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(dfn[u]<low[v])
{
cut[i]=cut[i^1]=true;
c[to[i]].push_back(to[i^1]);
c[to[i^1]].push_back(to[i]);
}
}
else if(v!=fa)
{
low[u]=min(low[u],dfn[v]);
}
}
}
int num[200005];
void dfs1(int u)
{
vis[u]=true;
num[get(u)]++;
for(int i=h[u];i;i=nx[i])
{
if(!cut[i])
{
int v=to[i];
if(!vis[v])
{
fa[v]=get(u);
w[fa[v]]+=w[v];
w[v]=0;
dfs1(v);
}
}
}
}
void dfs2(int u)
{
for(int v:a[u])
{
if(v!=fa[u])
{
fa[v]=u;
d[v]=d[u]+w[u];
dfs2(v);
}
}
}
void dfs3(int u)
{
for(int v:a[u])
{
if(v!=fa[u])
{
d[v]=d[u]+w[u];
dfs3(v);
}
}
}
int f[200005],l[200005];
void dp(int u)
{
for(int v:a[u])
{
if(v!=fa[u])
{
dp(v);
f[u]=max(f[u],l[u]+l[v]);
l[u]=max(l[u],l[v]);
}
}
f[u]+=w[u]+d[u];
l[u]+=w[u];
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
a[i].clear();
c[i].clear();
dfn[i]=vis[i]=num[i]=f[i]=l[i]=0;
h[i]=0;
fa[i]=i;
}
for(int i=1;i<=n;i++)
{
cin>>w[i];
}
tot=1;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
tot=0;
tarjan(1,0);
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
dfs1(i);
}
}
vector<int>dcc;
for(int i=1;i<=n;i++)
{
if(i==fa[i]&&num[i]>1)
{
dcc.push_back(i);
}
}
for(int i=2;i<=2*m+1;i+=2)
{
if(cut[i])
{
int u=get(to[i]),v=get(to[i^1]);
a[u].push_back(v);
a[v].push_back(u);
}
}
ans=0;
if(dcc.empty())
{
fa[1]=d[1]=0;
dfs2(1);
memset(d,0,sizeof(d[0])*(n+1));
dp(1);
}
else
{
fa[dcc[0]]=d[dcc[0]]=0;
dfs2(dcc[0]);
memset(vis,false,sizeof(vis[0])*(n+1));
vis[0]=true;
for(int x:dcc)
{
while(!vis[x])
{
vis[x]=true;
ans+=w[x];
w[x]=0;
x=fa[x];
}
}
dfs3(dcc[0]);
dp(dcc[0]);
}
cout<<ans+*max_element(f+1,f+n+1)<<endl;
}
return 0;
}