A层邀请赛2
终于快填完坑了,只差一个进化了
A. inversions
发现各个长度中的逆序对个数互不影响,而某个长度内的逆序对个数只会是正/反数列中逆序对个数,其只与长度大于等于它的区间翻转次数有关,所以用归并排序预处理每个长度对应的逆序对数,每次累加即可
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = (1 << 20) + 55;
typedef unsigned long long ull;
typedef long long ll;
int a[maxn], q[maxn], n ,m, threshold, cnt;
ull k1, k2;
ull xorShift128Plus() {
ull k3 = k1, k4 = k2;
k1 = k4;
k3 ^= (k3 << 23);
k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
return k2 + k4;
}
void gen(int n, int m, int threshold, ull _k1, ull _k2) {
k1 = _k1, k2 =_k2;
for (int i = 1; i <= (1 << n); i++) a[i] = xorShift128Plus() % threshold + 1;
for (int i = 1; i <= m; i++) q[i] = xorShift128Plus() % (n + 1);
}
int ls[maxn], t[maxn];
bool now[25]; ll rm[21], las, rl[23];
void solve(int l, int r, int dep, bool op){
if(l >= r)return;
int mid = (l + r) >> 1;
solve(l, mid, dep - 1, op);
solve(mid + 1, r, dep - 1, op);
int p1 = l, pos = l - 1;
for(int p2 = mid + 1; p2 <= r; ++p2){
while(p1 <= mid && ls[p1] <= ls[p2]){t[++pos] = ls[p1]; ++p1;}
if(op)rl[dep] += mid - p1 + 1; else rm[dep] += mid - p1 + 1;
t[++pos] = ls[p2];
}
while(p1 <= mid)t[++pos] = ls[p1++];
for(int i = l; i <= r; ++i)ls[i] = t[i];
}
int main(){
cin >> n >> m >> threshold >> k1 >> k2;
gen(n, m, threshold, k1, k2);
if(n == 0){
printf("0\n");
return 0;
}
int mx = (1 << n);
for(int i = 1; i <= mx; ++i)ls[i] = a[i];
sort(ls + 1, ls + mx + 1);
cnt = unique(ls + 1, ls + mx + 1) - ls - 1;
for(int i = 1; i <= mx; ++i)a[i] = lower_bound(ls + 1, ls + cnt + 1, a[i]) - ls;
for(int i = 1; i <= mx; ++i)ls[i] = a[i];
solve(1, mx, n, 1);
for(int i = 1; i <= mx; ++i)ls[i] = a[mx - i + 1];
solve(1, mx, n, 0);
ll ans = 0;
for(int i = 1; i <= m; ++i){
ll las = 0;
now[q[i]] = 1 - now[q[i]];
int fl = 1;
for(int i = n; i >= 1; --i){
if(now[i])fl = 1 - fl;
if(!fl)las += rm[i];
else las += rl[i];
}
ans = ans xor ( las * i);
}
printf("%lld\n",ans);
return 0;
}
选择
询问离线,删边变加边,倒着考虑,每条非树边会更新两个点路径,查询其实是查两点之间路径是否全部标记过
可以树剖维护,还可以(我不会)
不过我用了一个奇妙做法
不难发现两点之间路径全被标记过这个东西可以用并查集维护,而并到一个集合上之后树的具体形态已经不重要了
所以可以用类似并查集路径压缩的方法,每次把路径上遍历的点父亲都改成,在并查集中合并即可
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
const int maxn = 500005;
struct edge{
int u,v;
edge(){}
edge(int x, int y){
u = min(x ,y);
v = max(x, y);
}
friend bool operator < (const edge x, const edge y){return x.u == y.u ? x.v < y.v : x.u < y.u;}
};
struct Edge{int net,to;}e[maxn << 1 | 1];
struct opt{int op,u,v,ans;}o[maxn];
struct SET{
int f[maxn];
void pre(int x){
for(int i = 1; i <= x; ++i)f[i] = i;
}
int fa(int x){return f[x] = f[x] == x ? x : fa(f[x]);}
bool hb(int x, int y){
x = fa(x); y = fa(y);
if(x != y)f[x] = y;
else return false;
return true;
}
}S1, S2;
char c[3];
int n, m, q, head[maxn], tot = 1;
void add(int u, int v){
e[++tot].net = head[u];
head[u] = tot;
e[tot].to = v;
}
void link(int u, int v){
if(S1.hb(u, v) == 0)return;
add(u, v);add(v, u);
}
int dep[maxn],fa[maxn];
void dfs(int x){
for(int i = head[x]; i; i = e[i].net){
int v = e[i].to;
if(dep[v])continue;
dep[v] = dep[x] + 1;
fa[v] = x;
dfs(v);
}
}
int LCA(int u, int v){
while(fa[u] != fa[v]){
if(dep[fa[u]] > dep[fa[v]])u = fa[u];
else v = fa[v];
}
return u == v ? u : fa[u];
}
void modify(int u, int v){
int lca = LCA(u, v);
if(lca == 0)return;
while(u != lca && u){
S2.hb(u, lca);
int lx = u;
u = fa[u];
fa[lx] = lca;
}
u = v;
while(u != lca && u){
S2.hb(u, lca);
int lx = u;
u = fa[u];
fa[lx] = lca;
}
}
set<edge>s;
int main(){
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= m; ++i){int u ,v; scanf("%d%d",&u, &v); s.insert(edge(u,v));}
for(int i = 1; i <= q; ++i){
scanf("%s",c); scanf("%d%d", &o[i].u,&o[i].v);
if(c[0] == 'Z')o[i].op = 1,s.erase(edge(o[i].u, o[i].v));
else o[i].op = 0;
}
S1.pre(n);
for(auto x : s) link(x.u, x.v);
for(int i = q; i >= 1; --i)if(o[i].op) link(o[i].u, o[i].v);
for(int i = 1; i <= n; ++i)if(!dep[i]) dep[i] = 1,dfs(i);
S1.pre(n); S2.pre(n);
for(auto x : s)if(S1.hb(x.u, x.v) == 0)modify(x.u, x.v);
for(int i = q; i >= 1; --i)
if(o[i].op){if(S1.hb(o[i].u, o[i].v))continue;modify(o[i].u,o[i].v);}
else o[i].ans = S2.fa(o[i].u) == S2.fa(o[i].v) ? 1 : 0;
for(int i = 1; i <= q; ++i)if(!o[i].op){if(o[i].ans)printf("Yes\n");else printf("No\n");}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】