zoukankan      html  css  js  c++  java
  • 2019南昌网络赛I:Yukino With Subinterval(CDQ) (树状数组套主席树)

    题意:询问区间有多少个连续的段,而且这段的颜色在[L,R]才算贡献,每段贡献是1。 有单点修改和区间查询。

    思路:46min交了第一发树套树,T了。 稍加优化多交几次就过了。

    不难想到,除了L这个点,其他的点都可以只统计这一段的段首。把位置看成x,颜色看成y,就成了二维平面就矩形内点的个数,这就是裸的树套树或者CDQ了。

    树套树:34**ms。

    /*
    2019南昌网络赛I。
    询问区间有多少个连续的段,而且这段的颜色在[L,R]才算贡献,每段贡献是1。 有单点修改和区间查询。
    也可以CDQ来做,常数小很多。
    */
    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    struct in{
        int l,r,sum;
    }s[maxn*150];
    int a[maxn],rt[maxn],N,M,cnt;
    void add(int &Now,int L,int R,int pos,int v)
    {
        if(!Now) Now=++cnt; s[Now].sum+=v;
        if(L==R) return ;int Mid=(L+R)>>1;
        if(pos<=Mid) add(s[Now].l,L,Mid,pos,v);
        else add(s[Now].r,Mid+1,R,pos,v);
    }
    void Add(int x,int pos,int v)
    {
        while(x<=N){
            add(rt[x],1,N,pos,v);
            x+=(-x)&x;
        }
    }
    int query(int Now,int L,int R,int l,int r)
    {
        if(!Now||s[Now].sum==0) return 0;
        if(l<=L&&r>=R) return s[Now].sum;
        int Mid=(L+R)>>1,res=0;
        if(l<=Mid) res+=query(s[Now].l,L,Mid,l,r);
        if(r>Mid) res+=query(s[Now].r,Mid+1,R,l,r);
        return res;
    }
    int Query(int x,int L,int R)
    {
        if(L>R||x==0) return 0;
        int res=0; while(x){
            res+=query(rt[x],1,N,L,R);
            x-=(-x)&x;
        } return res;
    }
    void read(int &x){
        x=0; char c=getchar();
        while(c>'9'||c<'0') c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    }
    int main()
    {
        scanf("%d%d",&N,&M);
        rep(i,1,N) {
            read(a[i]);
            if(a[i]!=a[i-1]) Add(i,a[i],1);
        }
        int opt,pos,L,R,x,y;
        while(M--){
            read(opt);
            if(opt==2){
                read(L); read(R); read(x); read(y);
                int ans=Query(R,x,y)-Query(L-1,x,y);
                if(a[L]==a[L-1]&&a[L]<=y&&a[L]>=x) ans++;
                printf("%d
    ",ans);
            }
            else {
                read(pos); read(x);
                if(a[pos]==x) continue;
                if(a[pos]!=a[pos-1]) Add(pos,a[pos],-1);
                if(pos+1!=N&&a[pos+1]!=a[pos]) Add(pos+1,a[pos+1],-1);
                a[pos]=x;
                if(a[pos]!=a[pos-1]) Add(pos,a[pos],1);
                if(pos+1!=N&&a[pos+1]!=a[pos]) Add(pos+1,a[pos+1],1);
            }
        }
        return 0;
    }
    View Code

    CDQ:700ms。

    /*
    2019南昌网络赛I:
    */
    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    struct in{
        int opt,x,y,z,id;
        //opt=0是修改,否则是查询。
        //opt=1表示时间为x,查询[1,x],[y,z]的矩形面积
        //时间为第一维,x为第二维,y到z为第三维
    }s[maxn<<3],q[maxn<<3];
    int c[maxn],ans[maxn],tot,Q;
    int sum[maxn],N,M;
    void add(int x,int val)
    {
        for(int i=x;i<=N;i+=(-i)&i) sum[i]+=val;
    }
    int query(int x){
        int res=0;
        for(int i=x;i;i-=(-i)&i) res+=sum[i];
        return res;
    }
    void CDQ(int y,int z,int L,int R) //x在[y,z]区间,操作在[L,R]。 不停地对x进行分治,并把[L,R]进行相应的划分
    {
        if(L>=R) return ;
        if(y>z) return ;
        if(y==z){ //特殊的一行
            rep(i,L,R) {
               if(!s[i].opt) add(s[i].y,s[i].z);
               if(s[i].opt!=0) ans[s[i].id]+=s[i].opt*(query(s[i].z)-query(s[i].y-1));
            }
            rep(i,L,R) if(!s[i].opt) add(s[i].y,-s[i].z);
            return ;
        }
        int Mid=(y+z)>>1,F=L,C=L;
        rep(i,L,R) {
            if(s[i].x<=Mid) C++;
            if(!s[i].opt&&s[i].x<=Mid) add(s[i].y,s[i].z);
            if(s[i].opt!=0&&s[i].x>Mid) ans[s[i].id]+=s[i].opt*(query(s[i].z)-query(s[i].y-1));
        }
        rep(i,L,R) if(!s[i].opt&&s[i].x<=Mid) add(s[i].y,-s[i].z);
        rep(i,L,R) if(s[i].x<=Mid) q[F++]=s[i]; else q[C++]=s[i];
        rep(i,L,R) s[i]=q[i];
        CDQ(y,Mid,L,F-1); CDQ(Mid+1,z,F,R);
    }
    int main()
    {
        scanf("%d%d",&N,&M);
        rep(i,1,N) {
            scanf("%d",&c[i]);
            if(c[i]!=c[i-1]) s[++tot]=in{0,i,c[i],1,0};
        }
        int opt,L,R,x,y;
        rep(i,1,M){
            scanf("%d",&opt);
            if(opt&1){
                scanf("%d%d",&x,&y);
                if(y==c[x]) continue;
                if(c[x]!=c[x-1]) s[++tot]=in{0,x,c[x],-1,0};
                if(x<N&&c[x]!=c[x+1]) s[++tot]=in{0,x+1,c[x+1],-1,0};
                c[x]=y;
                if(c[x]!=c[x-1]) s[++tot]=in{0,x,c[x],1,0};
                if(x<N&&c[x]!=c[x+1]) s[++tot]=in{0,x+1,c[x+1],1,0};
            }
            else {
                scanf("%d%d%d%d",&L,&R,&x,&y); Q++;
                s[++tot]=in{1,R,x,y,Q};
                s[++tot]=in{-1,L,x,y,Q};
                if(c[L]>=x&&c[L]<=y) ans[Q]++;
            }
        }
        CDQ(1,N,1,tot);
        rep(i,1,Q) printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    使用Pencil进行UI草图设计
    模板机制在Zend Framework
    数组/链表高效去重(算法题
    Docker常用命令总结
    vscode中的git使用
    二分搜索模板
    多年没有管理的技术博客了,即日起开始管理起技术博客
    c# office不同版本下中使用Excel
    最近在忙项目,好久不来
    中秋 国庆
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11510753.html
Copyright © 2011-2022 走看看