zoukankan      html  css  js  c++  java
  • 2019 CCPC wannfly winter camp Day 8

    E - Souls-like Game

    直接线段树合并矩阵会被卡T掉,因为修改的复杂度比询问的复杂度多一个log,所以我们考虑优化修改。

    修改的瓶颈在于打lazy的时候, 所以我们预处理出每个修改矩阵2的幂次,然后直接更新。

    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3)
    //#pragma GCC optimize(4)
    //#pragma GCC optimize("unroll-loops")
    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define db double
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 998244353
    #define ld long double
    //#define C 0.5772156649
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pll pair<ll,ll>
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    #define ull unsigned long long
    //#define base 1000000000000000000
    #define fin freopen("a.txt","r",stdin)
    #define fout freopen("a.txt","w",stdout)
    #define fio ios::sync_with_stdio(false);cin.tie(0)
    inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    inline void sub(ll &a,ll b){a-=b;if(a<0)a+=mod;}
    inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
    template<typename T>inline T const& MAX(T const &a,T const &b){return a>b?a:b;}
    template<typename T>inline T const& MIN(T const &a,T const &b){return a<b?a:b;}
    inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
    inline ll qp(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c,b>>=1;}return ans;}
    
    using namespace std;
    
    const ull ba=233;
    const db eps=1e-9;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    const int N = 200000+10,maxn=4000000+10,inf=0x3f3f3f3f;
    
    int nn, tot;
    
    struct Matrix {
        int a[3][3];
        Matrix() {
            memset(a, 0, sizeof(a));
        }
        void read() {
            for(int i=0;i<3;i++)for(int j=0;j<3;j++)scanf("%d",&a[i][j]);
        }
        void pr()
        {
            for(int i=0;i<3;i++) {
                for(int j=0;j<3;j++)printf("%d ",a[i][j]);
                puts("");
            }
        }
        void init() {
            for(int i = 0; i < 3; i++)
                a[i][i] = 1;
        }
        Matrix operator * (const Matrix &B) const {
            Matrix C;
            for(int i = 0; i < 3; i++)
                for(int j = 0; j < 3; j++)
                    for(int k = 0; k < 3; k++)
                        C.a[i][j] = (C.a[i][j] + 1ll * a[i][k] * B.a[k][j]) % mod;
            return C;
        }
        Matrix operator ^ (int b) {
            Matrix C; C.init();
            Matrix A = (*this);
            while(b) {
                if(b & 1) C = C * A;
                A = A * A; b >>= 1;
            }
            return C;
        }
    } o[N<<2], tmp[N][20];
    int lazy[N<<2], depth[N<<2], cnt;
    bool ok[N<<2];
    
    void pushup(int rt){o[rt]=o[rt<<1]*o[rt<<1|1];}
    void pushdown(int l,int r,int rt)
    {
        if(!ok[rt]) return;
        int m=(l+r)>>1;
        o[rt<<1]=tmp[lazy[rt]][depth[rt<<1]];
        o[rt<<1|1]=tmp[lazy[rt]][depth[rt<<1|1]];
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        ok[rt<<1] = ok[rt<<1|1] = true;
        ok[rt] = false;
    }
    
    void build(int l,int r,int rt,int deep)
    {   depth[rt] = deep;
        ok[rt] = false;
        if(l==r){if(l <= nn) o[rt].read();return;}
        int m=(l+r)>>1;
        build(ls, deep-1);build(rs, deep-1);
        pushup(rt);
    }
    
    void update(int L,int R,int who,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            o[rt] = tmp[who][depth[rt]];
            lazy[rt] = who;
            ok[rt] = true;
            return;
        }
        pushdown(l,r,rt);
        int m=(l+r)>>1;
        if(L<=m)update(L,R,who,ls);
        if(m<R)update(L,R,who,rs);
        pushup(rt);
    }
    Matrix query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R) {
            return o[rt];
        }
        pushdown(l,r,rt);
        int m=(l+r)>>1;
        Matrix te;te.init();
        if(L<=m)te=te*query(L,R,ls);
        if(m<R)te=te*query(L,R,rs);
        return te;
    }
    
    int main() {
        int n, m, p;
        scanf("%d%d",&n,&m);n--;
        nn = n;
        for(p = 0; (1 << p) < n; p++);
        n = 1 << p;
        build(1, n, 1, p);
        while(m--)
        {
            int op,l,r;scanf("%d%d%d",&op,&l,&r);
            if(op==1) {
                cnt++;
                tmp[cnt][0].read();
                for(int i = 1; i < 20; i++)
                    tmp[cnt][i] = tmp[cnt][i - 1] * tmp[cnt][i - 1];
                update(l,r,cnt,1,n,1);
            } else {
                --r;
                Matrix te=query(l,r,1,n,1);
                ll ans=0;
                for(int i=0;i<3;i++)for(int j=0;j<3;j++)add(ans,1ll*te.a[i][j]);
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
    /*
    */
    View Code

    G - 穗乃果的考试

    我们考虑 求和 i * f[ i ]  实际上就是求每个点被多少矩形包括。

    那么 求和 i * i * f[ i ] 就是求任意两个点对被多少矩形包括之和, 这个我们可以用树状数组维护。

    #include<bits/stdc++.h>
    #define LL long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PLL pair<LL, LL>
    #define PLI pair<LL, int>
    #define PII pair<int, int>
    #define SZ(x) ((int)x.size())
    #define ull unsigned long long
    using namespace std;
    
    const int N = 2000 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 998244353;
    const double eps = 1e-8;
    
    struct Bit {
        LL a[N];
        void modify(int x, int val) {
            for(int i = x; i < N; i += i & -i)
                a[i] += val;
        }
        LL sum(int x) {
            LL ans = 0;
            for(int i = x; i; i -= i & -i)
                ans += a[i];
            return ans;
        }
        LL query(int L, int R) {
            if(L > R) return 0;
            return sum(R) - sum(L - 1);
        }
    } bit[2];
    
    int n, m;
    char s[N][N];
    
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            scanf("%s", s[i] + 1);
        LL ans = 0;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                pre = ans;
                if(s[i][j] == '1') {
                    ans = (ans + 2 * bit[0].sum(j) * (n-i+1) % mod * (m-j+1) % mod);
                    ans = (ans + 2 * bit[1].query(j + 1, m) * j % mod * (n-i+1) % mod);
                    bit[0].modify(j, i * j);
                    bit[1].modify(j, i * (m-j+1));
                    ans = (ans + 1ll * i * j * (n-i+1) % mod * (m-j+1) % mod) % mod;
                }
            }
        }
        printf("%lld
    ", ans);
        return 0;
    }
    
    /*
    */
    View Code

    A - Aqours

    我们可以发现一颗子树返回上来的最优节点一定是编号最小的节点。

    这题卡dfs, 我按叶子节点的编号顺序把边排序,然后用栈模拟dfs。

    #include<bits/stdc++.h>
    #define LL long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PLL pair<LL, LL>
    #define PLI pair<LL, int>
    #define PII pair<int, int>
    #define SZ(x) ((int)x.size())
    #define ull unsigned long long
    using namespace std;
    
    const int N = 3e6 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 998244353;
    const double eps = 1e-8;
    
    int n, cnt, tot, p[N], mn[N], mnlen[N], bottom[N];
    int ans[N];
    
    vector<int> G[N];
    vector<int> leaf;
    
    bool cmp(const int& a, const int& b) {
        return mn[a] < mn[b];
    }
    
    struct node {
        int who, len, p;
    };
    
    inline int read() {
        char ch = getchar(); int x = 0, f = 1;
        while(ch < '0' || ch > '9') {
            if(ch == '-') f = -1;
            ch = getchar();
        } while('0' <= ch && ch <= '9') {
            x = x * 10 + ch - '0';
            ch = getchar();
        } return x * f;
    }
    
    int main() {
        n = read();
        if(n == 1) {
            puts("1 -1");
            return 0;
        }
        for(int i = 2; i <= n; i++) {
            p[i] = read();
            G[p[i]].push_back(i);
        }
        for(int i = 1; i <= n; i++)
            mn[i] = inf, mnlen[i] = inf, bottom[i] = inf;
        for(int i = n; i > 1; i--) {
            if(!SZ(G[i])) mn[i] = i, bottom[i] = 0, leaf.push_back(i);
            mn[p[i]] = min(mn[p[i]], mn[i]);
        }
        reverse(leaf.begin(), leaf.end());
        for(int i = 1; i <= n; i++)
            sort(G[i].begin(), G[i].end(), cmp);
        stack<PII> stk;
        stk.push({1, 0});
        while(SZ(stk)) {
            PII u = stk.top(); stk.pop();
            if(!u.se) {
                ans[u.fi] = mnlen[u.fi];
            }
            if(u.se >= SZ(G[u.fi])) {
                bottom[p[u.fi]] = min(bottom[p[u.fi]], bottom[u.fi] + 1);
            } else {
                mnlen[u.fi] = min(mnlen[u.fi], bottom[u.fi]);
                stk.push(mk(u.fi, u.se + 1));
                mnlen[G[u.fi][u.se]] = mnlen[u.fi] + 1;
                stk.push(mk(G[u.fi][u.se], 0));
            }
        }
        for(auto& u : leaf) {
            int val = ans[u];
            printf("%d %d
    ", u, val >= inf ? -1 : val);
        }
        return 0;
    }
    
    /*
    */
    View Code
  • 相关阅读:
    Python全栈-第四课 学习笔记
    Python全栈-第三课 学习笔记
    Python全栈-第二课 学习笔记
    计算机网络技术-交换基础和Vlan间路由 学习笔记
    Linux运维-04系统管理和操作命令
    Linux运维-03远程连接
    Linux运维-02操作系统和系统安装(虚拟机)
    Linux运维-01硬件组成概念介绍
    计算机网络技术-路由-OSPF 学习笔记
    python基础 day17 模拟博客园登录
  • 原文地址:https://www.cnblogs.com/CJLHY/p/10333344.html
Copyright © 2011-2022 走看看