T1
直接按照定義推式子,就可以用矩陣加速優化。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 998244353;
int len;
struct mat {
int a[3][3];
mat(){memset(a,0,sizeof a);}
inline mat operator *(const mat &o)const {
mat re;
for(int i = 0; i < len; ++i)
for(int j = 0; j < len; ++j)
for(int k = 0; k < len; ++k)
re.a[i][j] = (re.a[i][j] + 1ll * a[i][k] * o.a[k][j]) % mod;
return re;
}
inline mat operator ^(LL b) const {
mat re, A = (*this);
for(int i = 0; i < len; ++i) re.a[i][i] = 1;
while(b) {
if(b&1) re = re * A;
A = A * A; b >>= 1;
}
return re;
}
}tr, ans;
inline int qpow(int a, LL b) {
int re = 1;
while(b) {
if(b&1) re = 1ll * re * a % mod;
a = 1ll * a * a % mod; b >>= 1;
}
return re;
}
LL n; int k;
void solve0() { printf("%d\n", qpow(2, n-1)); }
void solve1() {
len = 2;
tr.a[0][0] = 1; tr.a[0][1] = 1;
tr.a[1][0] = 1; tr.a[1][1] = 2;
ans.a[0][0] = 1;
ans.a[1][0] = 2;
if(n == 1) printf("%d\n", 1);
else {
ans = (tr ^ (n-1)) * ans;
printf("%d\n", ans.a[0][0]);
}
}
void solve2() {
len = 3;
tr.a[0][0] = 1; tr.a[0][1] = 2; tr.a[0][2] = 1;
tr.a[1][0] = 0; tr.a[1][1] = 1; tr.a[1][2] = 1;
tr.a[2][0] = 1; tr.a[2][1] = 2; tr.a[2][2] = 2;
ans.a[0][0] = 1;
ans.a[1][0] = 1;
ans.a[2][0] = 2;
if(n == 1) printf("%d\n", 1);
else {
ans = (tr ^ (n-1)) * ans;
printf("%d\n", ans.a[0][0]);
}
}
int main () {
freopen("generate.in", "r", stdin);
freopen("generate.out", "w", stdout);
scanf("%lld%d", &n, &k);
if(k == 0) solve0();
else if(k == 1) solve1();
else if(k == 2) solve2();
}
T2
線段樹查詢回傳值時沒開longlong。爆成60分。
#include<bits/stdc++.h>
using namespace std;
inline void read(int &x) {
char ch; while(!isdigit(ch=getchar()));
for(x=ch-'0'; isdigit(ch=getchar()); x=x*10+ch-'0');
}
typedef long long LL;
const int MAXN = 100005;
const int MAXM = 200005;
int n, m, a[MAXN], lst[32], pos[MAXN][32];
struct node {
int l, r, id;
inline bool operator <(const node &o)const {
return l > o.l;
}
};
vector<node>q[32];
LL ans[MAXM];
int lz[MAXN<<2];
LL sum[MAXN<<2];
void build(int i, int l, int r) {
lz[i] = sum[i] = 0;
if(l == r) return;
int mid = (l + r) >> 1;
build(i<<1, l, mid);
build(i<<1|1, mid+1, r);
}
inline void pd(int i, int l, int mid, int r) {
if(lz[i]) {
lz[i<<1] += lz[i], lz[i<<1|1] += lz[i];
sum[i<<1] += 1ll * (mid-l+1) * lz[i];
sum[i<<1|1] += 1ll * (r-mid) * lz[i];
lz[i] = 0;
}
}
void add(int i, int l, int r, int x, int y) {
if(x == l && r == y) {
lz[i]++;
sum[i] += r-l+1;
return;
}
int mid = (l + r) >> 1;
pd(i, l, mid, r);
if(y <= mid) add(i<<1, l, mid, x, y);
else if(x > mid) add(i<<1|1, mid+1, r, x, y);
else {
add(i<<1, l, mid, x, mid);
add(i<<1|1, mid+1, r, mid+1, y);
}
sum[i] = sum[i<<1] + sum[i<<1|1];
}
LL query(int i, int l, int r, int x) {
if(r <= x) return sum[i];
int mid = (l + r) >> 1; LL re = 0;
pd(i, l, mid, r);
if(x > mid) re += query(i<<1|1, mid+1, r, x);
return re + query(i<<1, l, mid, x);
}
int main () {
freopen("sequence.in", "r", stdin);
freopen("sequence.out", "w", stdout);
read(n), read(m);
for(int i = 0; i < 30; ++i) lst[i] = n+1;
for(int i = 1; i <= n; ++i) read(a[i]);
for(int i = n; i >= 1; --i) {
for(int j = 0; j < 30; ++j) {
if(!(a[i]>>j&1)) lst[j] = i;
pos[i][j+1] = lst[j];
}
sort(pos[i] + 1, pos[i] + 30 + 1);
pos[i][0] = i; pos[i][31] = n+1;
}
for(int i = 1, l, r, k; i <= m; ++i) {
read(l), read(r), read(k);
q[k].push_back((node){l, r, i});
}
for(int k = 0; k <= 30; ++k) if(q[k].size()) {
build(1, 1, n);
sort(q[k].begin(), q[k].end());
int siz = q[k].size(), j = n;
for(int i = 0, l, r, L, R; i < siz; ++i) {
l = q[k][i].l, r = q[k][i].r;
while(l <= j) {
L = pos[j][30-k], R = pos[j][30-k+1] - 1;
if(L <= R) add(1, 1, n, L, R);
--j;
}
ans[q[k][i].id] += query(1, 1, n, r);
}
}
for(int i = 1; i <= m; ++i) printf("%lld\n", ans[i]);
}
T3
就是[HNOI2015]接水果的強制在線版本。
具體做法是把離線數據結構換成樹套樹或者kd樹。
#include<bits/stdc++.h>
const int MAXN = 100005;
const int MAXM = 800005;
const int LOG = 16;
using namespace std;
int n, m, dep[MAXN], f[MAXN][LOG+1], in[MAXN], out[MAXN], tmr;
int fir[MAXN], nxt[MAXN<<1], to[MAXN<<1], cnt;
inline void line(int x, int y) { nxt[++cnt] = fir[x], fir[x] = cnt, to[cnt]= y; }
void dfs(int u, int ff){
in[u] = ++tmr, f[u][0] = ff, dep[u] = dep[ff] + 1;
for(int i = fir[u]; i; i = nxt[i]) if(to[i] != ff) dfs(to[i], u);
out[u] = tmr;
}
inline int ser(int u, int v){
for(int i = 0, d = dep[u]-dep[v]-1; d; d>>=1, ++i) if(d&1) u = f[u][i];
return u;
}
inline int lca(int u, int v){
if(dep[u] < dep[v]) swap(u, v);
for(int i = 0, d = dep[u]-dep[v]; d; d>>=1, ++i) if(d&1) u = f[u][i];
if(u == v) return u;
for(int i = LOG; i >= 0; i--) if(f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
return f[u][0];
}
struct node{
int d[2], mn[2], mx[2], ch[2], siz, s, v, nd;
void upd(node *t){
mn[0] = mx[0] = d[0], mn[1] = mx[1] = d[1], s = v, siz = 1;
for(int i = 0; i < 2; i++) if(ch[i]){
siz += t[ch[i]].siz, s += t[ch[i]].s;
for(int j = 0; j < 2; j++)
mn[j] = min(mn[j], t[ch[i]].mn[j]),
mx[j] = max(mx[j], t[ch[i]].mx[j]);
}
}
}t[MAXM];
int rt, sz, id[MAXM], *tmp, X, Y, ans;
template<int D>bool cmp(int i,int j){return t[i].d[D] < t[j].d[D];}
bool (*fun[2])(int, int) = {cmp<0>, cmp<1>};
void build(int &i, int l, int r, int D){
if(l > r) return (void)(i=0);
int o = (l+r)>>1; nth_element(id + l, id + o, id + r + 1, fun[D]), i = id[o];
build(t[i].ch[0], l, o-1, D^1), build(t[i].ch[1], o+1, r, D^1);
t[i].upd(t), t[i].nd=D;
}
void ins(int &i, int x, int D){
if(!i) { t[i=x].upd(t), t[i].nd = D; return; }
ins(t[i].ch[fun[D](i,x)], x, D^1), t[i].upd(t);
if(t[i].siz*0.75 < max(t[t[i].ch[0]].siz, t[t[i].ch[1]].siz)) tmp = &i;
}
void biang(int i){ if(!i) return; id[++*id] = i, biang(t[i].ch[0]), biang(t[i].ch[1]); }
void qry(int i){
if(!i || t[i].mn[0] > X || t[i].mn[1] > Y) return;
if(t[i].mx[0] <= X && t[i].mx[1] <= Y) { ans += t[i].s; return; }
if(t[i].d[0] <= X && t[i].d[1] <= Y) ans += t[i].v;
qry(t[i].ch[0]), qry(t[i].ch[1]);
}
inline void AP(int x, int y, int v){
t[++sz].d[0] = x, t[sz].d[1] = y, t[sz].v = v, tmp = 0, ins(rt, sz, 0);
if(tmp) id[0] = 0, biang(*tmp), build(*tmp, 1, id[0], t[*tmp].nd);
}
inline void AM(int a, int b, int c, int d){
AP(a, c, 1);
if(d<n) AP(a, d+1, -1);
if(b<n) AP(b+1, c, -1);
if(d<n&&b<n) AP(b+1, d+1, 1);
}
int arr[MAXN], val[MAXN];
inline int qsum(int i){int s=0;for(; i; i-=i&-i) s += arr[i]; return s; }
inline void upd(int i, int d){for(; i<=n; i+=i&-i) arr[i] += d; }
int main() {
freopen("water.in", "r", stdin);
freopen("water.out", "w", stdout);
int x, y;
char op;
scanf("%d%d", &n, &m);
for(int i = 1; i < n; i++)
scanf("%d%d", &x,&y),
line(x, y),
line(y, x);
dfs(1,0);
for(int j = 1;j <= LOG; j++)
for(int i = 1; i <= n; i++)
f[i][j] = f[f[i][j-1]][j-1];
while(m--) {
while(!isalpha(op = getchar()));
scanf("%d%d", &x, &y), x ^= ans, y ^= ans; if(in[x] > in[y]) swap(x, y);
if(op == 'A') {
if(x == y) {
val[x]++,
upd(in[x], 1),
upd(out[x]+1, -1);
continue;
}
if(in[x] <= in[y] && out[y] <= out[x]){
int z = ser(y, x);
AM(1, in[z]-1, in[y], out[y]);
if(out[z] < n)
AM(in[y], out[y], out[z]+1, n);
}
else
AM(in[x], out[x], in[y], out[y]);
}
else{
X = in[x], Y = in[y];
int z = lca(x,y);
ans = qsum(X) + qsum(Y) - 2*qsum(in[z]) + val[z],
qry(rt);
printf("%d\n",ans);
}
}
}