超级经典套路题,徐神1h就开了这道题然后开始写,后面我接力上去写了个DSU on Tree加线段树,这就是我们热血沸腾的组合技啊
首先原问题等价于,每个点有一个颜色,每个连通块的权值定义为其中出现次数最多的颜色的值
图的权值定义为所有连通块的权值和,现在要对于每一条边求出,断掉这条边后图的权值是多少
看到断边和连通性,很容易想到求出桥,显然不是桥的那些边删不删对答案没有影响,可以预先计算出
然后根据经典结论,将一个无向图边双缩点后,得到的一定是个森林,因此只要考虑在树上断一条边求解原问题
树上的断边又等价于选出一个子树,求出它的贡献以及删去整个子树后剩下部分的贡献
直接DSU on Tree扫描子树,同时线段树分别维护子树内和子树外每种颜色出现的次数即可,总复杂度O(nlog2n)
#include<bits/stdc++.h>constexprint $n = 200005;
std::vector<std::pair<int, int>> out[$n];
int dfn[$n], low[$n], tarjan_O;
std::vector<std::pair<int, int>> edge;
std::vector<bool> is_bridge;
int fa[$n];
bool vis[$n];
inlineintfather(int i){
if(fa[i] == i) return i;
return fa[i] = father(fa[i]);
}
voidtarjan(int u, int pre){
low[u] = dfn[u] = ++tarjan_O;
vis[u] = true;
int son = 0;
int pre_cnt = 0;
for(auto [v, id]: out[u]) {
if(v == pre && pre_cnt == 0) { pre_cnt += 1; continue; }
if(!dfn[v]) {
son += 1;
tarjan(v, u);
if(low[u] > low[v]) low[u] = low[v];
if(low[v] > dfn[u]) is_bridge[id] = true;
} elseif(low[u] > dfn[v]) {
low[u] = dfn[v];
}
}
}
int n, m,C;
int a[$n], ans[$n], baseline;
std::vector<int> hkr[$n];
int ans_partial[$n];
std::map<int, int> rst[$n];
std::map<int, int> dfs1(int cur, int pre){
std::map<int, int> res {};
vis[cur] = true;
for(auto hkr: hkr[cur]) res[hkr] += 1;
for(auto [ch, id]: out[cur]) if(ch != pre) {
auto s = dfs1(ch, cur);
if(s.size() > res.size()) std::swap(s, res);
for(auto [k, v]: s) res[k] += v;
}
return res;
}
#define CI const int&classSegment_Tree{
private:
int mx[$n<<2];
public:
#define TN CI now=1,CI l=1,CI r=C#define LS now<<1,l,mid#define RS now<<1|1,mid+1,rinlinevoidupdata(CI pos,CI mv,TN){
if (l==r) return (void)(mx[now]+=mv); int mid=l+r>>1;
if (pos<=mid) updata(pos,mv,LS); elseupdata(pos,mv,RS);
mx[now]=std::max(mx[now<<1],mx[now<<1|1]);
}
inlineintquery(void){
return mx[1];
}
#undef TN#undef LS#undef RS}IN,OUT;
int son[$n],sz[$n],bid[$n];
inlinevoidgetson(CI now,CI fa=0){
sz[now]=1; son[now]=0; vis[now]=true;
for (auto [to,_]:out[now]) if (to!=fa)
{
getson(to,now); sz[now]+=sz[to];
if (sz[to]>sz[son[now]]) son[now]=to,bid[now]=_;
}
}
inlinevoidtravel(CI now,CI fa,CI tp){
for (auto x:hkr[now]) IN.updata(x,tp),OUT.updata(x,-tp);
for (auto [to,_]:out[now]) if (to!=fa) travel(to,now,tp);
}
inlinevoidDSU(CI outer,CI now,CI fa=0,CI id=-1,CI flag=0){
for (auto [to,_]:out[now]) if (to!=fa&&to!=son[now]) DSU(outer,to,now,_,0);
if (son[now]) DSU(outer,son[now],now,bid[now],1);
for (auto [to,_]:out[now]) if (to!=fa&&to!=son[now]) travel(to,now,1);
for (auto x:hkr[now]) IN.updata(x,1),OUT.updata(x,-1);
if (~id) ans[id]=outer+IN.query()+OUT.query();
if (!flag) travel(now,fa,-1);
}
voidsolve(CI outer,CI root){
for (auto [x,y]:rst[root]) OUT.updata(x,y);
getson(root); DSU(outer,root);
for (auto [x,y]:rst[root]) OUT.updata(x,-y);
}
#undef CIvoidwork(){
std::cin >> n >> m; C=0; tarjan_O = 0;
for(int i = 1; i <= n; ++i) low[i] = dfn[i] = 0;
for(int i = 1; i <= n; ++i) std::cin >> a[i],C=std::max(C,a[i]);
for(int i = 1; i <= n; ++i) out[i].clear();
edge.resize(m), is_bridge.assign(m, false);
for(int i = 0; i < m; ++i) {
auto &[f, t] = edge[i];
std::cin >> f >> t;
out[f].emplace_back(t, i), out[t].emplace_back(f, i);
}
for(int i = 1; i <= n; ++i) vis[i] = false;
for(int i = 1; i <= n; ++i) if(!vis[i]) tarjan(i, i);
// for(int i = 0; i < m; ++i) if(is_bridge[i]) std::cerr << edge[i].first << " <-> " << edge[i].second << char(10);// std::cerr << "-------\n";// return ;for(int i = 1; i <= n; ++i) fa[i] = i;
for(int i = 0; i < m; ++i) if(!is_bridge[i]) fa[father(edge[i].first)] = father(edge[i].second);
for(int i = 1; i <= n; ++i) out[i].clear();
std::set<std::pair<int, int>> edge_fuck;
for(int i = 0; i < m; ++i) if(is_bridge[i]) {
auto [_f, _t] = edge[i];
int f = father(_f), t = father(_t);
if(f > t) std::swap(f, t);
if(edge_fuck.find({f, t}) != edge_fuck.end()) continue;
edge_fuck.insert({f, t});
out[f].emplace_back(t, i), out[t].emplace_back(f, i);
}
for(int i = 1; i <= n; ++i) hkr[i].clear();
for(int i = 1; i <= n; ++i) hkr[father(i)].push_back(a[i]);
baseline = 0;
for(int i = 1; i <= n; ++i) vis[i] = false;
for(int i = 1; i <= n; ++i) if(fa[i] == i && !vis[i]) {
rst[i] = dfs1(i, i);
ans_partial[i] = 0;
// std::cerr << "i = " << i << char(10);// for(auto [k, v]: rst[i]) std::cerr << "k, v = " << k << ", " << v << char(10);for(auto [k, v]: rst[i]) if(v > ans_partial[i]) ans_partial[i] = v;
baseline += ans_partial[i];
// std::cerr << "ans_partial[" << i << "] = " << ans_partial[i] << char(10); } else rst[i].clear();
// std::cerr << baseline << char(10);// std::cerr << "-------\n";// return ;for(int i = 1; i <= n; ++i) vis[i] = false;
for(int i = 1; i <= n; ++i) if(fa[i] == i && !vis[i]) solve(baseline-ans_partial[i],i);
for(int i = 0; i < m; ++i) is_bridge[i]
? std::cout << ans[i] << char(i == m - 1 ? 10 : 32)
: std::cout << baseline << char(i == m - 1 ? 10 : 32);
return ;
}
intmain(){
// freopen("B.in","r",stdin); std::ios::sync_with_stdio(false);
int T; std::cin >> T; while(T--) work();
return0;
}
4|0C. Flippy Sequence
分类讨论题,找出两个串不同的极长区间的个数,记为cnt,则:
cnt>2,显然无解
cnt=2,手玩以下会发现一定恰有6种方法,而且样例给出了这种情况所以很容易理解
cnt=1,刚开始被坑了以为和区间长度有关,后面仔细想了下发现就是2×(n−1)
cnt=0,两次选的区间相同,方案数为n(n+1)2
#include<cstdio>#include<iostream>#define RI register int#define CI const int&usingnamespace std;
constint N=1e6+5;
int t,n; char a[N],b[N];
intmain(){
for (scanf("%d",&t);t;--t)
{
RI i; scanf("%d%s%s",&n,a+1,b+1);
int cnt=0,lst=0;
for (i=1;i<=n;++i) if (a[i]==b[i])
{
if (lst+1<=i-1) ++cnt; lst=i;
}
if (lst+1<=n) ++cnt;
if (cnt>2) { puts("0"); continue; }
if (cnt==2) { puts("6"); continue; }
if (cnt==1) printf("%d\n",2*(n-1));
elseprintf("%lld\n",1LL*n*(n+1)/2LL);
}
return0;
}
#include<cstdio>#include<iostream>#define RI register int#define CI const int&usingnamespace std;
constint N=1005;
int t,n,k;
intmain(){
for (scanf("%d",&t);t;--t)
{
RI i,j; scanf("%d%d",&n,&k);
auto lowbit=[&](CI x)
{
return x&-x;
};
if (k>lowbit(n)-1) { puts("Impossible"); continue; }
for (i=1;i<=k;++i) for (j=0;j<n;++j) printf("%d%c",(j^i)+1," \n"[j==n-1]);
}
return0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2023-04-27 2022年第十三届蓝桥杯大赛软件类决赛C/C++大学A组真题