湖师大集训记录

湖师大集训记录

lyoi303:「2017 山东一轮集训 Day1」Sum

吕老板讲的方法只有50….

TLE

#include <bits/stdc++.h>
using namespace std;

int p, n, m;
const int mod = 998244353, g = 3;

int power(int a, int n)
{
    int ans = 1, b = a;
    for (register int i = 0; i <= 30; i++) {
        if ((n>>i)&1) ans = (long long)ans*b%mod;
        b = (long long)b*b%mod;
    }
    return ans;
}

inline int inv(int a)
{ return power(a, mod-2); }

const int MAXN = 2049;
int rev[MAXN];
void NTT(int a[], int n, int flag)
{
    int m = 1, lgn = 0;
    while (m < n) lgn++, m <<= 1;
    rev[0] = 0;
    for (register int i = 1; i < n; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(lgn-1));
    for (register int i = 0; i < n; i++)
        if (rev[i] < i) swap(a[i], a[rev[i]]);
    for (register int k = 1; k <= n; k <<= 1) {
        int dw = power(g, (mod-1)/k);
        if (flag == -1) dw = inv(dw);
        for (register int i = 0; i < n; i += k) {
            int w = 1;
            for (register int j = 0; j < k>>1; j++) {
                int u = a[i+j], t = (long long)w*a[i+j+(k>>1)]%mod;
                a[i+j] = (u+t)%mod, a[i+j+(k>>1)] = ((u-t)%mod+mod)%mod;
                w = (long long)w*dw%mod;
            }
            }
        }
    if (flag == -1) {
        int Inv = inv(n);
        for (register int i = 0; i < n; i++)
            a[i] = (long long)Inv*a[i]%mod;
    }
}

int B[2049], C[2049];
void mul(int a[2049], int M, int b[2049], int c[2049]) // $a = b\oplus c$
{
    memcpy(B, b, sizeof B), memcpy(C, c, sizeof C);
    memset(a, 0, sizeof B);
    int n = 1;
    while (n < M) n <<= 1;
    n <<= 1; // todo here
    NTT(B, n, 1), NTT(C, n, 1);
    for (register int i = 0; i < n; i++)
        a[i] = (long long)B[i]*C[i]%mod;
    NTT(a, n, -1);
    for (register int i = M; i < 2048; i++)
        a[i] = 0;
}

struct node {
    int N, Pow;  // 10^N = Pow;
    int A[55][2049];
    void print()
    {
        puts("Matrix : ");
        for (int i = 0; i < p; i++) {
            for (int j = 0; j <= m; j++)
                cerr << A[i][j] << " ";
            cerr << endl;
        }
        puts("End Matrix.");
    }
    node() {
        memset(A, 0, sizeof A);
    }
    friend node operator * (node &a, node &b)
    {
        node ret;
        static int A[MAXN];
        memset(A, 0, sizeof A);
        ret.N = a.N+b.N, ret.Pow = (long long)a.Pow*b.Pow%p;
        for (register int i = 0; i < p; i++) {
            for (register int j = 0; j < p; j++) {
                int M = ((long long)i*b.Pow%p+j)%p;
                mul(A, m+1, a.A[i], b.A[j]);
                for (register int k = 0; k <= m; k++) (ret.A[M][k] += A[k]) %= mod;
            }
        }
        return ret;
    }
};

node power(node a, int n)
{
    node ans;
    int flag = -1;
    for (int i = 0; i <= 30; i++) {
        if ((n>>i) == 0) break;
        if ((n>>i)&1) {
            if (flag == -1) ans = a, flag = 1;
            else ans = ans*a;
        }
        a = a*a;
    }
    return ans;
}

node A;

int a[MAXN], b[MAXN], c[MAXN];
int main()
{
    scanf("%d%d%d", &n, &p, &m);
    A.N = 1, A.Pow = 10;
    for (int j = 0; j <= min(m, 9); j++)
    A.A[j%p][j]++;
    A = power(A, n);
    int ans = 0;
    for (int i = 0; i <= m; i++) {
        ans = (ans+A.A[0][i])%mod;
        printf("%d ", ans);
    }
    puts("");
    return 0;
}

upd: 原来是我走神了QwQ。
做循环卷积的时候要先全部DFT,卷完了全部IDFT,复杂度少一个 log
AC…

#include <bits/stdc++.h>
using namespace std;

int p, n, m;
const int mod = 998244353, g = 3;

int power(int a, int n)
{
    int ans = 1, b = a;
    for (register int i = 0; i <= 30; i++) {
        if ((n>>i)&1) ans = (long long)ans*b%mod;
        b = (long long)b*b%mod;
    }
    return ans;
}

inline int inv(int a)
{ return power(a, mod-2); }

const int MAXN = 2049;
int rev[MAXN];
void NTT(int a[], int n, int flag)
{
    int m = 1, lgn = 0;
    while (m < n) lgn++, m <<= 1;
    rev[0] = 0;
    for (register int i = 1; i < n; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(lgn-1));
    for (register int i = 0; i < n; i++)
        if (rev[i] < i) swap(a[i], a[rev[i]]);
    for (register int k = 1; k <= n; k <<= 1) {
        int dw = power(g, (mod-1)/k);
        if (flag == -1) dw = inv(dw);
        for (register int i = 0; i < n; i += k) {
            int w = 1;
            for (register int j = 0; j < k>>1; j++) {
                int u = a[i+j], t = (long long)w*a[i+j+(k>>1)]%mod;
                a[i+j] = (u+t)%mod, a[i+j+(k>>1)] = ((u-t)%mod+mod)%mod;
                w = (long long)w*dw%mod;
            }
            }
        }
    if (flag == -1) {
        int Inv = inv(n);
        for (register int i = 0; i < n; i++)
            a[i] = (long long)Inv*a[i]%mod;
    }
}

int B[2049], C[2049];
void mul(int a[2049], int M, int b[2049], int c[2049]) // $a = b\oplus c$
{
    memcpy(B, b, sizeof B), memcpy(C, c, sizeof C);
    memset(a, 0, sizeof B);
    int n = 1;
    while (n < M) n <<= 1;
    n <<= 1; // todo here
    cerr << n << endl;
    NTT(B, n, 1), NTT(C, n, 1);
    for (register int i = 0; i < n; i++)
        a[i] = (long long)B[i]*C[i]%mod;
    NTT(a, n, -1);
    for (register int i = M; i < 2048; i++)
        a[i] = 0;
}

struct node {
    int N, Pow;  // 10^N = Pow;
    int A[55][2049];
    void display()
    {
        puts("Matrix : ");
        for (int i = 0; i < p; i++) {
            for (int j = 0; j <= m; j++)
                cerr << A[i][j] << " ";
            cerr << endl;
        }
        puts("End Matrix.");
    }
    node() {
        memset(A, 0, sizeof A);
    }
    friend node operator * (node a, node b)
    {
        node ret;
        static int C[55][MAXN], d[MAXN];
        memset(C, 0, sizeof C);
        ret.N = a.N+b.N, ret.Pow = (long long)a.Pow*b.Pow%p;
        int np = 1;
        while (np < m+1) np <<= 1;
        np <<= 1; // todo here
            for (int i = 0; i < p; i++) NTT(a.A[i], np, 1), NTT(b.A[i], np, 1);
        for (int i = 0; i < p; i++) {
            for (int j = 0; j < p; j++) {
                int M = ((long long)i*b.Pow%p+j)%p;
                for (int k = 0; k < np; k++)
                        C[M][k] = (C[M][k]+(long long)a.A[i][k]*b.A[j][k]%mod)%mod;
            }
        }
        for (int i = 0; i < p; i++) {
            NTT(a.A[i], np, -1), NTT(b.A[i], np, -1),
            NTT(C[i], np, -1);
            for (int k = 0; k <= m; k++) ret.A[i][k] = (ret.A[i][k]+C[i][k])%mod;
        }
        return ret;
    }
};

node power(node a, int n)
{
    node ans;
    int flag = -1;
    for (int i = 0; i <= 30; i++) {
        if ((n>>i) == 0) break;
        if ((n>>i)&1) {
            if (flag == -1) ans = a, flag = 1;
            else ans = ans*a;
        }
        a = a*a;
    }
    return ans;
}

node A;

int a[MAXN], b[MAXN], c[MAXN];
int main()
{
        scanf("%d%d%d", &n, &p, &m);
    A.N = 1, A.Pow = 10;
        for (int j = 0; j <= min(m, 9); j++)
        A.A[j%p][j]++;
    A = power(A, n);
    int ans = 0;
    for (int i = 0; i <= m; i++) {
        ans = (ans+A.A[0][i])%mod;
        printf("%d ", ans);
    }
    puts("");
    return 0;
}

lyoi306「2017 山东一轮集训 Day2」Pair

考虑匹配条件 ai+bjh ,令 Bj=hbj 也就是 aiBj 。显然,一个序列匹配当且仅当排序后匹配。考虑排序后 n ak n Bk的情况,容易发现,匹配当且仅当(排序后)对于任何一个前缀, a 的数量不少于B。如果把 a 看成左括号,B看成右括号,就是经典的括号序列匹配问题了。 a=1,B=1 用线段树维护前缀和的区间最小值即可。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 150005;
int gt[MAXN];
int n, m, h;

struct p {
    int dt, pos;
    friend bool operator < (const p &a, const p &b)
    {
        if (a.dt == b.dt) return a.pos < b.pos;
        return a.dt < b.dt;
    }
}a[MAXN], b[MAXN], dx[MAXN+MAXN];

int A[MAXN], B[MAXN], dx_top = 0;

void dx_init()
{
    for (int i = 1; i <= m; i++) dx[++dx_top] = b[i];
    for (int i = 1; i <= n; i++) dx[++dx_top] = a[i];
    sort(dx+1, dx+dx_top+1);
}

inline int dx_num(const p &a)
{ return lower_bound(dx+1, dx+dx_top+1, a)-dx; }

struct tree {
    int dat[MAXN*4], l[MAXN*4], r[MAXN*4], lc[MAXN*4], rc[MAXN*4], tag[MAXN*4], top, root;
    inline void clear()
    { top = root = 0; }
    tree()
    { clear(); }
    void build(int &nd, int opl, int opr)
    {
        nd = ++top, dat[nd] = tag[nd] = 0, l[nd] = opl, r[nd] = opr;
        if (opl < opr)
            build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);
    }
    void pdw(int nd)
    {
        if (!nd) return;
        if (lc[nd]) tag[lc[nd]] += tag[nd], tag[rc[nd]] += tag[nd];
        dat[nd] += tag[nd], tag[nd] = 0;
    }
    inline void update(int nd)
    { if (lc[nd]) dat[nd] = min(dat[lc[nd]], dat[rc[nd]]); }
    void modify(int nd, int opl, int opr, int dt)
    {
        pdw(nd);
        if (l[nd] == opl && r[nd] == opr) tag[nd] += dt;
        else {
            int mid = (l[nd]+r[nd])/2;
            if (opr <= mid) modify(lc[nd], opl, opr, dt);
            else if (opl > mid) modify(rc[nd], opl, opr, dt);
            else modify(lc[nd], opl, mid, dt), modify(rc[nd], mid+1, opr, dt);
            pdw(lc[nd]), pdw(rc[nd]), update(nd);
        }
    }
    int query(int nd, int opl, int opr)
    {
        pdw(nd);
        if (l[nd] == opl && r[nd] == opr) return dat[nd];
        int mid = (l[nd]+r[nd])/2;
        if (opr <= mid) return query(lc[nd], opl, opr);
        else if (opl > mid) return query(rc[nd], opl, opr);
        else return min(query(lc[nd], opl, mid), query(rc[nd], mid+1, opr));
    }
    void display()
    {
        for (int i = 1; i <= dx_top; i++) printf("%d ", query(root, i, i));
        puts("");
    }
} seg;

int main()
{
    scanf("%d%d%d", &n, &m, &h);
        for (int i = 1; i <= m; i++)
        scanf("%d", &b[i].dt), b[i].dt = h-b[i].dt, b[i].pos = -i;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i].dt), a[i].pos = i;
    dx_init();
    for (int i = 1; i <= m; i++) B[i] = dx_num(b[i]);//, printf("%d ", B[i]);
    for (int i = 1; i <= n; i++) A[i] = dx_num(a[i]);//, printf("%d ", A[i]);
    seg.build(seg.root, 1, dx_top);
    for (int i = 1; i <= m; i++) seg.modify(seg.root, B[i], dx_top, 1);
    int cnt = 0;
    for (int i = 1; i <= m; i++) seg.modify(seg.root, A[i], dx_top, -1);
    for (int i = 1; i <= n; i++) {
        if (seg.query(seg.root, 1, dx_top) >= 0) cnt++;
        seg.modify(seg.root, A[i], dx_top, 1);
        if (i+m > n) break;
        seg.modify(seg.root, A[i+m], dx_top, -1);
    }
    printf("%d\n", cnt);
    return 0;
}

lyoi323. 「2017 山东一轮集训 Day7」养猫

神奇的费用流…最大流限制/费用计算的好模型。

from visit_world
把 1 到 n 串成一条链
考虑上限:
想象你带了 mx 个小弟在链上走,到一个位置 p,你可以派出一个小弟去获得对应收益,但是他在 p + k 的时候才能归队
考虑下限:
在 p 这里派出一个小弟,会使得 [p, p+k) 上走“主干道”的小弟减少一名。
因此,我们限制“主干道”的流量为 mx - mi 即可满足下限

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005;
int n, k, ms, me;
int mx, mn;

int s[MAXN], e[MAXN];

struct node {
    int to, next, flow;
    long long cost;
    int neg;
} edge[MAXN*200];
int head[MAXN], top = 0;
inline int push(int i, int j, int f, long long c)
{
    ++top, edge[top] = (node) {j, head[i], f, c, top+1}, head[i] = top;
    ++top, edge[top] = (node) {i, head[j], 0, -c, top-1}, head[j] = top;
    return top-1;
}

long long dis[MAXN];
int vis[MAXN];
queue<int> que;
int pre[MAXN], pre_edge[MAXN];
int S = MAXN-1, T = MAXN-2;
const long long inf = 1e14;
bool spfa(int &flow, long long &cost)
{
    memset(vis, 0, sizeof vis), memset(dis, 127/3, sizeof dis);
    vis[S] = 1, dis[S] = 0, que.push(S);
    while (!que.empty()) {
        int nd = que.front(); que.pop(), vis[nd] = 0;
        for (int i = head[nd]; i; i = edge[i].next) {
            int to = edge[i].to;
            if (!edge[i].flow || dis[to] <= dis[nd]+edge[i].cost) continue;
            dis[to] = dis[nd]+edge[i].cost, pre[to] = nd, pre_edge[to] = i;
            if (!vis[to])
                vis[to] = 1, que.push(to);
        }
    }
    if (dis[T] > inf) return 0;;
    int mf = INT_MAX;
    for (int i = T; i != S; i = pre[i]) mf = min(mf, edge[pre_edge[i]].flow);
    for (int i = T; i != S; i = pre[i]) 
        edge[pre_edge[i]].flow -= mf, edge[edge[pre_edge[i]].neg].flow += mf;
    cost += dis[T]*mf;
    flow += mf;
    return 1;
}

void mcf(int &flow, long long &cost)
{
    cost = flow = 0;
    while (spfa(flow, cost));
}

int eg[MAXN];

int main()
{
    scanf("%d%d%d%d", &n, &k, &ms, &me); // change t, t \le me, k-t \le ms \rightarrow t \ge k-ms
    mx = k-ms, mn = me; // [mn, mx]
    long long cnt = 0;
    for (int i = 1; i <= n; i++) scanf("%d", &s[i]), cnt += s[i]; // sleep
    for (int i = 1; i <= n; i++) scanf("%d", &e[i]);
    push(S, 1, mx, 0), push(n, T, mx, 0);
    for (int i = 1; i < n; i++) {
        if (i >= k) push(i, i+1, mx-mn, 0);
        else push(i, i+1, mx, 0);
    }
    for (int i = 1; i <= n; i++) {
        int t = i+k <= n?i+k:T;
        eg[i] = push(i, t, 1, -e[i]+s[i]);
    }
    int flow;
    long long cost;
    mcf(flow, cost);
    printf("%lld\n", cnt-cost);
    for (int i = 1; i <= n; i++) {
        if (edge[eg[i]].flow)
            putchar('S');
        else putchar('E');
    }
    puts("");
    return 0;
}

loj#6060. 「2017 山东一轮集训 Day1」Set

首先有 x1x2 为定值,设为 x 。考虑x的每一位,如果为1,由于必然一边为1一边为0,对和的贡献不变;如果为0,则应该尽可能让更高位两边全为1。

做法1:首先取出 x 为0的位做一遍最大异或找到x2中必须为1的位置,然后作出线性基。贪心的从高到低放置每一位,用异或方程组判断下面是否有解「太麻烦了根本写不出来…」
// 但这个思路扩展性更好,可以出道题233

做法2:考虑统一处理,在贪心求最大异或的时候改变贪心顺序,首先是 x 为0的位,然后是为1的。直接做就好了。

#include <bits/stdc++.h>
using namespace std;

struct linear_base {
    long long A[70];
    void push(long long x, long long lim)
    {
        for (int i = 60; i >= 0; i--) {
            if (lim&(1ll<<i)) continue;
            if (!(x&(1ll<<i))) continue;
            if (!A[i]) { A[i] = x; return;}
            else x ^= A[i];
        }
            for (int i = 60; i >= 0; i--) {
            if (!(lim&(1ll<<i))) continue;
            if (!(x&(1ll<<i))) continue;
            if (!A[i]) { A[i] = x; return; }
            else x ^= A[i];
        }
    }
    long long max_xor(long long lim)
    {
        long long val = 0;
        for (int i = 60; i >= 0; i--)
            if (!(lim&(1ll<<i)) && !(val&(1ll<<i)))
                val ^= A[i];
        for (int i = 60; i >= 0; i--)
            if ((lim&(1ll<<i)) && !(val&(1ll<<i)))
                val ^= A[i];
            return val;
    }
} lb;
int n;
long long val[100005], xr = 0;

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%lld", &val[i]),  xr ^= val[i];
    for (int i = 1; i <= n; i++)
        lb.push(val[i], xr);
    printf("%lld\n", xr^lb.max_xor(xr));
    return 0;
}

loj #6068. 「2017 山东一轮集训 Day4」棋盘

套路题。首先行列划分,中间连线表示格子,考虑计算代价。不妨在SRow的地方计算一行的代价, ColumnT 的地方计算一列的代价。一行/列中有 n 个棋子,产生的代价为n(n1)2,这是一个下凸函数,直接差分建边就好了。

可以动态加边,但不加也过了。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 3005;
struct node {
    int to, next, flow, cost, neg;
} edge[MAXN*3005];
int head[MAXN], top = 0;
inline void push(int i, int j, int f, int c)
{
    ++top, edge[top] = (node){j, head[i], f, c, top+1}, head[i] = top;
    ++top, edge[top] = (node){i, head[j], 0, -c, top-1}, head[j] = top;
}

int dis[MAXN], vis[MAXN];
queue<int> que;
int pre[MAXN], pre_edge[MAXN];
const int S = MAXN-1, T = MAXN-2, inf = 233333333;

bool spfa(int &flow, int &cost)
{
    memset(dis, 127/3, sizeof dis), memset(vis, 0, sizeof vis);
    vis[S] = 1, dis[S] = 0, que.push(S);
    while (!que.empty()) {
        int nd = que.front(); que.pop(); vis[nd] = 0;
        for (int i = head[nd]; i; i = edge[i].next) {
            int to = edge[i].to;
                if (edge[i].flow == 0 || dis[to] <= dis[nd]+edge[i].cost) continue;
            dis[to] = dis[nd]+edge[i].cost, pre[to] = nd, pre_edge[to] = i;
            if (!vis[to])
                vis[to] = 1, que.push(to);
        }
    }
    if (dis[T] > inf) return 0;
    int maxf = inf;
    for (int i = T; i != S; i = pre[i]) maxf = min(maxf, edge[pre_edge[i]].flow);
    for (int i = T; i != S; i = pre[i]) {
        edge[pre_edge[i]].flow -= maxf;
        edge[edge[pre_edge[i]].neg].flow += maxf;
    }
    flow += maxf, cost += maxf*dis[T];
    return 1;
}

void mcf(int &flow, int &cost)
{ while (spfa(flow, cost)); }

int top_pt = 0;

int n;
char str[55][55];
int ptlr[55][55], ptud[55][55];
int cnt = 0, g[MAXN], s = T-1;

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%s", str[i]+1);
        for (int j = 1; j <= n; j++)
            if (str[i][j] == '.')
                cnt++;
    }
    for (int i = 1; i <= n; i++) {
        int pt = 1;
        while (pt <= n) {
            while (pt <= n && str[i][pt] == '#') pt++;
            if (pt > n) continue;
            ++top_pt;
            for (int j = 0; j <= n; j++)
                push(s, top_pt, 1, j);
            while (pt <= n && str[i][pt] == '.') ptlr[i][pt++] = top_pt;
        }
    }
    for (int i = 1; i <= n; i++) {
        int pt = 1;
        while (pt <= n) {
            while (pt <= n && str[pt][i] == '#') pt++;
            if (pt > n) continue;
            ++top_pt;
            for (int j = 0; j <= n; j++)
                push(top_pt, T, 1, j);
            while (pt <= n && str[pt][i] == '.') ptud[pt++][i] = top_pt;
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (str[i][j] == '.')
                push(ptlr[i][j], ptud[i][j], 1, 0);
        }
    }
    g[0] = 0;
    int flow = 0, cost = 0;
    for (int i = 1; i <= cnt; i++) {
        push(S, s, 1, 0);
        mcf(flow, cost);
        //cerr << flow << endl;
        g[i] = cost;
    }
    int k; scanf("%d", &k);
    while (k--) {
        int t; scanf("%d", &t);
        printf("%d\n", g[t]);
    }
    return 0;
}

loj#2254. 「SNOI2017」一个简单的询问

考虑莫队。想到 get(l,r,x)=get(1,r,x)get(1,l1,x) 就很简单了。



#include <bits/stdc++.h>
using namespace std;

const int MAXN = 50005;

struct query {
    int l1, r1, l2, r2;
} qy[MAXN];

int sqrtN;
int n, q;

struct qs {
    int r1, r2;
    int id, num; // num = 0,1,2,3
    friend bool operator < (const qs &a, const qs &b)
    {
        if (a.r1/sqrtN == b.r1/sqrtN) return a.r2 < b.r2;
        return a.r1 < b.r1;
    }
} qys[MAXN*4];
int qtop = 0;

long long ans[MAXN][4];
int a[MAXN];
int A[MAXN], B[MAXN]; // 出现次数

void solve_q()
{
    sort(qys+1, qys+qtop+1);
    int L = qys[1].r1, R = qys[1].r2;
        for (int i = 1; i <= L; i++) A[a[i]]++;
    for (int j = 1; j <= R; j++) B[a[j]]++;
    long long Ans = 0;
    for (int i = 1; i <= n; i++) Ans += (long long)A[i]*B[i];
    for (int i = 1; i <= qtop; i++) {
        // cerr << qys[i].r1 << " -- " << qys[i].r2 << " " << A[1] << " " << B[1] << endl; 
        while (L < qys[i].r1) L++, A[a[L]]++, Ans += B[a[L]];
        while (L > qys[i].r1) A[a[L]]--, Ans -= B[a[L]], L--;
        while (R < qys[i].r2) R++, B[a[R]]++, Ans += A[a[R]];
        while (R > qys[i].r2) B[a[R]]--, Ans -= A[a[R]], R--;
        // cerr << Ans << endl;
        ans[qys[i].id][qys[i].num] = Ans;
    }
}

void solve()
{
    for (int i = 1; i <= q; i++) {
        qys[++qtop] = (qs) {qy[i].r1, qy[i].r2, i, 0};
        if (qy[i].l2 != 1) qys[++qtop] = (qs) {qy[i].r1, qy[i].l2-1, i, 1};
        else ans[i][1] = 0;
        if (qy[i].l1 != 1) qys[++qtop] = (qs) {qy[i].l1-1, qy[i].r2, i, 2};
        else ans[i][2] = 0;
        if (qy[i].l1 != 1 && qy[i].l2 != 1) qys[++qtop] = (qs) {qy[i].l1-1, qy[i].l2-1, i, 3};
        else ans[i][3] = 0;

    }
    solve_q();
    for (int i = 1; i <= q; i++) 
        printf("%lld\n", ans[i][0]-ans[i][1]-ans[i][2]+ans[i][3]);
}

int main()
{
    scanf("%d", &n), sqrtN = ceil(sqrt(n));
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    scanf("%d", &q);
    for (int i = 1; i <= q; i++)
        scanf("%d%d%d%d", &qy[i].l1, &qy[i].r1, &qy[i].l2, &qy[i].r2);
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值