A

模拟

B

CF # 1458 简要题解_i++

C

我们将一个格子看成三元组 CF # 1458 简要题解_#define_02
那么 CF # 1458 简要题解_#define_03 就相当于是将所有 CF # 1458 简要题解_#define_04 变成 CF # 1458 简要题解_i++_05
我们维护一下三维的置换,对平移打上标记就可以了

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
cs int N = 1e3 + 50, M = 1e5 + 50;
int T, n, m, a[N][N], b[N][N];
int s[3], c[3]; char str[M];
void Main(){
cin >> n >> m;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
scanf("%d", &a[i][j]), --a[i][j];
for(int i = 0; i < 3; i++)
s[i] = 0, c[i] = i;
scanf("%s", str);
for(int i = 0; i < m; i++){
if(str[i] == 'L') --s[1];
if(str[i] == 'R') ++s[1];
if(str[i] == 'U') --s[0];
if(str[i] == 'D') ++s[0];
if(str[i] == 'I') swap(c[1], c[2]), swap(s[1], s[2]);
if(str[i] == 'C') swap(c[0], c[2]), swap(s[0], s[2]);
}
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++){
int t[3]; t[0] = i, t[1] = j, t[2] = a[i][j];
int x = t[c[0]], y = t[c[1]], z = t[c[2]];
x = ((x + s[0]) % n + n) % n;
y = ((y + s[1]) % n + n) % n;
z = ((z + s[2]) % n + n) % n; b[x][y] = z;
}
for(int i = 0; i < n; i++, puts(""))
for(int j = 0; j < n; j++)
cout << b[i][j] + 1 << " "; puts("");
}
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> T;
while(T--) Main();
return 0;
}

D

考虑将 CF # 1458 简要题解_#define_06 看成 CF # 1458 简要题解_#ifdef_07 连边,CF # 1458 简要题解_#define_08 看成 CF # 1458 简要题解_i++_09 连边
注意到反转一个子串相当于是将一条欧拉回路倒过来走
题目要求我们尽量向右走,我们每一步维护一下能不能向右走就可以了

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
cs int N = 1e6 + 50;
int T, n; char S[N];
int a[N], b[N];
void Main(){
scanf("%s", S + 1);
n = strlen(S + 1);
for(int i = 1, s = n; i <= n; i++){
if(S[i] == '0') ++a[s], ++s;
if(S[i] == '1') ++b[s], --s;
} int t = n;
while(true){
bool ok = a[t] && (b[t + 1] || !b[t]);
if(ok) putchar('0'), --a[t], ++t;
else if(b[t]) putchar('1'), --b[t], --t;
else break;
} puts("");
}
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> T;
while(T--) Main();
return 0;
}

E

将原问题放到二维平面上
不妨求出 CF # 1458 简要题解_#define_10 表示每个点是必败还是必胜
那么我们知道若 CF # 1458 简要题解_#ifdef_11 左边和下面都为 CF # 1458 简要题解_#define_08 那么它为 CF # 1458 简要题解_#define_06
同时 CF # 1458 简要题解_#ifdef_14 为可能为 CF # 1458 简要题解_#define_08 的点,每行每列只可能有一个点为 CF # 1458 简要题解_#define_08
于是我们设计一个算法:若当前为关键点,那么移动到 CF # 1458 简要题解_i++_17
若存在 CF # 1458 简要题解_#define_18 为关键点,那么移动到 CF # 1458 简要题解_#define_19
若存在 CF # 1458 简要题解_#ifdef_20 为关键点,那么移动到 CF # 1458 简要题解_#ifdef_21
否则当前 CF # 1458 简要题解_#define_22CF # 1458 简要题解_#define_08,此时只需要移动到 CF # 1458 简要题解_i++_17 就可以了
我们按 CF # 1458 简要题解_#define_25 做扫描线,维护 CF # 1458 简要题解_#ifdef_20CF # 1458 简要题解_#ifdef_27 的集合,复杂度 CF # 1458 简要题解_#ifdef_28

#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define fi first
#define se second
using namespace std;
cs int oo = 1e9 + 7;
typedef pair<int, int> pi;
cs int N = 1e5 + 50;
int n, m, ans[N], y[N];
map<pi, bool> ex;
map<int, vector<int> > G;
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> n >> m;
for(int i = 1, x, y; i <= n; i++){
scanf("%d%d", &x, &y);
ex[pi(x, y)] = true, G[x].pb(y);
} ex[pi(0, 0)] = 1, G[0].pb(0);
for(int i = 1, x, y; i <= m; i++){
scanf("%d%d", &x, &y);
if(!ex[pi(x, y)]) G[x].pb(-i), ::y[i] = y;
}
int lp = -1, lm = 0; set<int> Y;
for(auto z : G){
int x = z.fi; vector<int> e = z.se;
for(int i = lp + 1; i < x; ){
while(Y.find(lm) != Y.end()) ++lm;
auto t = Y.lower_bound(lm);
if(t == Y.end()) { lm += x - i; break; }
int dt = min(*t - lm, x - i); lm += dt, i += dt;
} while(Y.find(lm) != Y.end()) ++lm; int mn = oo;
for(int z : G[x]) if(z >= 0) mn = min(mn, z);
if(lm < mn) Y.insert(lm), mn = lm;
for(int z : G[x]) {
if(z >= 0) Y.insert(z);
else ans[-z] = y[-z] != mn;
} lp = x;
} for(int i = 1; i <= m; i++)
cout << (ans[i] ? "WIN" : "LOSE") << '\n';
return 0;
}

F

分治,考虑求出 CF # 1458 简要题解_#ifdef_29
我们对左边的每个后缀 CF # 1458 简要题解_#ifdef_30 求出 CF # 1458 简要题解_#define_31
表示用 CF # 1458 简要题解_#define_31 可以包住集合 CF # 1458 简要题解_#define_33 其中 CF # 1458 简要题解_#ifdef_34 是极小的
合并两个集合可以通过树上倍增实现
枚举左边的一个 CF # 1458 简要题解_#ifdef_30,那么 CF # 1458 简要题解_i++_36 可以分成三类,
CF # 1458 简要题解_i++_37
可以通过双指针来维护
对于前两类的贡献可以快速算,中间的贡献相当于是 CF # 1458 简要题解_#define_38
用点分树维护就可以了

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
typedef long long ll;
cs int N = 2e5 + 50;
int n; vector<int> G[N];
void add(int u, int v){ G[u].pb(v), G[v].pb(u); }

int sz[N], Mx, rt, all; bool ban[N];
void gsz(int u, int f){
sz[u] = 1; for(int v : G[u])
if(!ban[v] && v != f)
gsz(v, u), sz[u] += sz[v];
} void grt(int u, int f){
int mx = all - sz[u];
for(int v : G[u]) if(v != f && !ban[v])
grt(v, u), mx = max(mx, sz[v]);
if(mx < Mx) Mx = mx, rt = u;
} int anc[N], _d[N], d[20][N];
void dfs(int u, int f, int r){
for(int v : G[u])
if(v != f && !ban[v])
d[r][v] = d[r][u] + 1, dfs(v, u, r);
} void work(int u, int f){
gsz(u, 0); Mx = all = sz[u]; grt(u, 0);
ban[u = rt] = true;
_d[u] = _d[anc[u] = f] + 1;
dfs(u, 0, _d[u]);
for(int v : G[u]) if(!ban[v]) work(v, u);
}
int c[N]; ll b[N], _b[N];
void ins(int x, int vl){
for(int u = x, t = _d[x]; u; u = anc[u], --t){
if(t > 1) _b[u] += vl * d[t - 1][x];
c[u] += vl, b[u] += vl * d[t][x];
}
} ll ask(int x){
ll ans = b[x];
for(int u = x, v = anc[x], t =
_d[x] - 1; v; u = v, v = anc[v], --t)
ans += 1ll * (c[v] - c[u]) * d[t][x] + b[v] - _b[u];
return ans;
}

int dep[N], fa[N][20];
void pre_dfs(int u, int f){
dep[u] = dep[fa[u][0] = f] + 1;
for(int i = 1; i <= 17; i++)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for(int v : G[u]) if(v != f) pre_dfs(v, u);
} int LCA(int x, int y){
if(dep[x] < dep[y]) swap(x, y);
for(int i = 17; ~i; i--)
if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if(x == y) return x;
for(int i = 17; ~i; i--)
if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
} int dist(int x, int y){ return dep[x] + dep[y] - 2 * dep[LCA(x, y)]; }
int jmp(int x, int d){
for(int i = 17; ~i; i--)
if(d >= (1 << i)) d -= 1 << i, x = fa[x][i]; return x;
} int fnd(int x, int y, int d){
int l = LCA(x, y);
if(dep[x] - dep[l] >= d) return jmp(x, d);
d -= dep[x] - dep[l];
return jmp(y, dep[y] - dep[l] - d);
}
struct lll{
int u, r;
lll operator + (cs lll &z) {
int d = dist(u, z.u);
if(r + d <= z.r) return z;
if(z.r + d <= r) return *this;
int t = (r + z.r + d) / 2;
int p = fnd(u, z.u, t - r);
return (lll){p, t};
} bool in(cs lll &z){ return z.r + dist(u, z.u) <= r; }
bool _in(cs lll &z){ return z.r + dist(u, z.u) < r; }
} p[N]; ll Ans;
void cope(int l, int r){
if(l == r) return;
int mid = (l + r) >> 1;
p[mid] = (lll){mid, 0};
p[mid + 1] = (lll){mid + 1, 0};
for(int i = mid - 1; i >= l; i--)
p[i] = (lll){i, 0} + p[i + 1];
for(int i = mid + 2; i <= r; i++)
p[i] = (lll){i, 0} + p[i - 1];
int lp = mid, rp = mid + 1;
static ll s[N]; s[r + 1] = 0;
for(int i = r; i > mid; i--)
s[i] = s[i + 1] + p[i].r;
for(int i = mid; i >= l; i--){
while(rp <= r && !p[rp].in(p[i])) ins(p[rp].u, 1), ++rp;
while(lp < r && p[i]._in(p[lp + 1])) ++lp, ins(p[lp].u, -1);
Ans += s[rp] + 1ll * p[i].r * (lp - mid);
Ans += (s[lp + 1] - s[rp] + 1ll *
p[i].r * (rp - lp - 1) + ask(p[i].u)) / 2;
} while(lp + 1 < rp) ++lp, ins(p[lp].u, -1);
cope(l, mid), cope(mid + 1, r);
}
int main(){
#ifdef FSYo
freopen("1.in", "r", stdin);
#endif
cin >> n;
for(int i = 1, u, v; i < n; i++)
scanf("%d%d", &u, &v),
add(u, i + n), add(i + n, v);
pre_dfs(1, 0); work(1, 0);
cope(1, n);
cout << Ans << '\n';
}