路灯「APIO 2019」

题意

有、复杂,自己上网搜


思路

\((x,y)\) 表示从\(x\)到\(y\)联通的时间长度。

那么查询操作相当于二维平面上的单点查询。

对于每一个\(i\),维护一个最左能到达的\(lm\),和最右能到达的\(rm\)。

那么对于每一个更新操作,相当于对左上角为\((lm,i)\),右下角为\((i,rm)\)的矩形做修改。

于是就转换为类似「简单题」的题目了,可以CDQ分治解决,当然也可以直接上树套树。

代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

    template<typename T> inline void read (T &x) {
        x=0;T f=1;char c=getchar();
        for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
        for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    template<typename T> inline void write (T x) {
        if (x<0) putchar('-'),x=-x;
        if (x>=10) write(x/10);
        putchar(x%10+'0');
    }

}

using namespace StandardIO;

namespace Solve {
    #define int long long

    const int N=300003;

    int n,q,sta,cnt;
    char s[N];
    int tree[N];
    struct node {
        int t,x,y,id;
        int type,val,ans;
        node () {}
        node (int _t,int _x,int _y,int _ty,int _v,int _i) : t(_t),x(_x),y(_y),type(_ty),val(_v),id(_i) {}
    } w[N<<2],tmp[N<<2];
    int isQuery[N],ans[N];
    set<int> S;

    inline int pre (int x) {
        set<int>::iterator it=S.lower_bound(x);
        return *(--it);
    }
    inline int suc (int x) {
        set<int>::iterator it=S.upper_bound(x);
        return *it;
    }
    inline int lowbit (int x) {
        return x&(-x);
    }
    inline void update (int x,int v) {
        for (register int i=x; i<=n; i+=lowbit(i)) {
            tree[i]+=v;
        }
    }
    inline int query (int x) {
        int res=0;
        for (register int i=x; i; i-=lowbit(i)) {
            res+=tree[i];
        }
        return res;
    }
    inline bool cmpt (const node &x,const node &y) {
        if (x.t!=y.t) return x.t<y.t;
        if (x.x!=y.x) return x.x<y.x;
        return x.y<y.y;
    }
    inline bool cmpx (const node &x,const node &y) {
        if (x.x!=y.x) return x.x<y.x;
        return x.y<y.y;
    }
    void merge (int l,int r) {
        int mid=(l+r)>>1;
        int ptr_l=l,ptr_r=mid+1,num=l-1;
        while (ptr_l<=mid&&ptr_r<=r) {
            if (cmpx(w[ptr_l],w[ptr_r])) tmp[++num]=w[ptr_l++];
            else tmp[++num]=w[ptr_r++];
        }
        while (ptr_l<=mid) tmp[++num]=w[ptr_l++];
        while (ptr_r<=r) tmp[++num]=w[ptr_r++];
        for (register int i=l; i<=r; ++i) w[i]=tmp[i];
    }
    void CDQ (int l,int r) {
        if (l==r) return;
        int mid=(l+r)>>1;
        CDQ(l,mid),CDQ(mid+1,r);
        int ptr=l-1;
        for (register int i=mid+1; i<=r; ++i) {
            while (ptr<mid&&w[ptr+1].x<=w[i].x) {
                ++ptr;
                if (w[ptr].type==1) update(w[ptr].y,w[ptr].val);
            }
            if (w[i].type==2) w[i].ans+=query(w[i].y);
        }
        for (register int i=l; i<=ptr; ++i) {
            if (w[i].type==1) update(w[i].y,-w[i].val);
        }
        merge(l,r);
    }
    inline void MAIN () {
        read(n),read(q);
        S.insert(0),S.insert(n+1);
        scanf("%s",s+1);
        for (register int i=1; i<=n; ++i) {
            if (s[i]=='0') {
                S.insert(i);
            }
        }
        for (register int i=1; i<=q; ++i) {
            string op;int x,y;
            cin>>op;
            if (op[0]=='t') {
                read(x),s[x]^=1;
                int l=pre(x)+1,r=suc(x)-1;
//              cout<<l<<' '<<r<<endl;
                if (s[x]=='0') {
                    w[++cnt]=node(i,l,x,1,i,19);
                    w[++cnt]=node(i,l,r+1,1,-i,260);
                    w[++cnt]=node(i,x+1,x,1,-i,8);
                    w[++cnt]=node(i,x+1,r+1,1,i,17);
                    S.insert(x);
                } else {
                    w[++cnt]=node(i,l,x,1,-i,19);
                    w[++cnt]=node(i,l,r+1,1,i,260);
                    w[++cnt]=node(i,x+1,x,1,i,8);
                    w[++cnt]=node(i,x+1,r+1,1,-i,17);
                    S.erase(x);
                }
            } else {
                read(x),read(y);
                isQuery[i]=1,++sta;
                // node (int _t,int _x,int _y,int _ty,int _v,int _i) : t(_t),x(_x),y(_y),type(_ty),val(_v),id(_i) {}
                w[++cnt]=node(i,x,y-1,2,0,sta);
                if (suc(x)>y-1&&s[x]=='1'&&s[y-1]=='1') ans[sta]+=i;
            }
        }
        sort(w+1,w+cnt+1,cmpt);
//      for (register int i=1; i<=cnt; ++i) {
//          write(w[i].y),putchar('\n');
//      }
        CDQ(1,cnt);
        for (register int i=1; i<=cnt; ++i) {
            if (w[i].type==2) {
                ans[w[i].id]+=w[i].ans;
            }
        }
        for (register int i=1; i<=sta; ++i) {
            write(ans[i]),putchar('\n');
        }
    }

    #undef int
}

int main () {
    Solve::MAIN();
}

原文地址:https://www.cnblogs.com/ilverene/p/11395880.html

时间: 2024-07-31 14:31:46

路灯「APIO 2019」的相关文章

loj #3146. 「APIO 2019」路灯

loj #3146. 「APIO 2019」路灯 暴力的话就是查询\((l,r)\)之间是否全部是1,考虑如何优化查询 我们可以利用\(set\)来维护每一个全\(1\)区间和它出现的时间,具体的,用\((lp,rp,l,r)\)来表示\((lp,rp)\)的全\(1\)区间在时间\([l,r]\)中是存在的 那么对于一个在时间\(i\)的询问\((l_i,r_i)\),\((lp,rp,l,r)\)会对它产生贡献当且仅当\(lp\leq l_i,rp\geq r_i,i\geq l\),产生的

#3144. 「APIO 2019」奇怪装置

#3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个结论:该装置是一个特殊的时钟,它从过去的某个时间点开始测量经过的时刻数 \(t\),但该装置的创造者却将 \(t\) 用奇怪的方式显示出来.若从该装置开始测量到现在所经过的时刻数为 \(t\),装置会显示两个整数:\(x = ((t + \lfloor \frac{t}{B} \rfloor) \b

loj #3144. 「APIO 2019」奇怪装置

loj #3144. 「APIO 2019」奇怪装置 很明显的是我们需要找到\((x,y)\)的循环节的长度 当\(t=0\)时,\(x=0,y=0\) 当\(t\neq 0\)时,仍然要使的\(x=0,y=0\)的话,必有 \[ \begin{cases} t+\lfloor \frac{t}{B} \rfloor \equiv0(mod\ A)\t\equiv0(mod\ B) \end{cases} \] 记\(t=t'B\),则有\(A|t'(B+1)\),故\(t'\)最小为\(\fr

特别行动队「APIO 2010」

题意 有一个序列,要求将其分为任意部分.对于每一部分,其值为\(at^2+bt+c\),其中\(t\)为这一部分元素总和,\(a,b,c\)给定. 思路 容易推出状态转移方程为\(f[i]=min(f[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c)\) 朴素转移的时间复杂度为\(n^2\),考虑斜率优化. 假设对于决策点\(x,y\),存在\(f[x]+a*(sum[i]-sum[x])^2+b*(sum[i]-sum[x])+c>f[y]+a*(sum[

loj 3217 「PA 2019」Desant - 动态规划 - 复杂度分析

题目传送门 传送门 一个非常显然的想法是记录后面的值相邻两个之间在前面选了多少个数. 众所周知(比如我就不知道,我甚至以为它非常大),若干个和为 $n$ 的数的乘积最大为 $O(3^{n/3})$,最优方案是拆成若干个 3 和常数个 2. 然后 dp 即可. 时间复杂度 $O(n^23^{\frac{n + 1}{3}})$. Code #include <bits/stdc++.h> using namespace std; typedef bool boolean; const int N

「十二省联考 2019」字符串问题

「十二省联考 2019」字符串问题 解题思路 傻逼题.. 考虑问题转化为一个A串向其支配的所有B串的后缀A串连边,如果有环答案 \(-1\) 否则是这个 \(\text{DAG}\) 上最长路径,直接建图是 \(n^2\) 的,考虑优化建图即可. 由于 \(A,B\) 都是原串的一个子串,那么对原串的反串建 SAM,一个子串的后缀就是其所在节点上比它长的串以及,其子树里的所有串. 首先将所有 \(A,B\) 串在 SAM上用倍增定位并新建节点,把SAM上每个节点拆成入点和出点,对于SAM每一个节

「十二省联考 2019」字符串问题 解题报告

「十二省联考 2019」字符串问题 当场就去世了,我这菜人改了一下午 考虑一个A,B之间的连边实际表示了两个A之间的有向边,然后把A的连边处理好,就转成了拓扑排序找环+最长链 但是边数很多,考虑优化连边 A,B之间的连边显然没法优化的,考虑一个B可以表示所有它的后缀A 把串反向建出SAM,然后一个B的后缀就是par树的子树 可以拿倍增定位 好了这题就没了 注意到一个事情,定位的点可能重复,于是对SAM拆点,每个点挂一个vector表示一个A或者B的点在SAM的这个位置 然后考虑如何连边 一个B所

「CSPS 2019 十一」 贪心

一般来说,如果题目需要求一个最优解或者最小(大)花费之类的,而且除了暴力之外想不到什么好方法,那么就可能需要用贪心. 通常地,我们猜想一些步骤能不能直接使用贪心,然后再去证明这个贪心是对的. 有时候可能要多想几种贪心才能找到正确的那一种. New Year Snowmen Description 要堆起一个雪人,需要三个不同大小的雪球.现在有 \(n\) 个给定大小的雪球,问最多能堆起多少个雪人,并输出方案. Solution 每次用数量最多的三个雪球是最优的.可以用一个单调队列,每次取出最大的

进博会启幕 | 这场全球企业的「美丽机遇」,SAP准备好了!

编者按中国国际进口博览会的召开在体现中国开放.共赢的态度的同时,也为全球企业开创了更多在中国市场的「美丽机遇」.德国是首届中国国际进口博览会主宾国之一.在各行各业,都涌现出了许许多多德国企业缔造的行业神话.以SAP为代表的德国企业,在本次进博会中,吸引了众多媒体聚焦. △以上图片来自<新华网>.<光明日报>.<文汇报>等媒体的报道 首届中国国际进口博览会将于11月5日-10日在上海举行.作为全球首个以进口为主题的博览会,中国国际进口博览会受到广泛关注和期待. 进口博览会