zoukankan      html  css  js  c++  java
  • bzoj3236:[AHOI2013]作业

    传送门
    这个题网上大多数是使用莫队+树状数组的办法写的,实际上有着更优秀的算法:线段树分治+树状数组
    这个题是我在集训队论文上看到的,发现这个思想十分优秀,但是我貌似并不能很好的实现它。
    这个做法的思路大概是:首先建一棵权值线段树,对于线段树的每个区间存权值范围在区间内的所有数,再将所有的操作都存入线段树中(分开存),因为权值线段树内的每个区间都限制了权值的范围,然后就可以对于线段树的每个区间去查询位置在([l,r])之间的数有多少,第一问可以随便搞,对于第二问一个简洁的方法就是记下每种权值最后出现的位置,保证它只出现一遍就行了,修改查询用树状数组就可以优秀的解决。
    时间复杂度我不会证,论文上写的是(O((n+Q)log^2n))(Q为询问数,n为数的个数)
    细节可以看代码(代码实现参考了yww大佬的博客):

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    void read(int &x) {
        char ch; bool ok;
        for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
        for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define max(a,b) (a>b?a:b)
    #define rg register
    int n,m,num,las[100001],z[100001],ans[1000010],ans1[1000010];
    struct oo{int l,r;}s[400001];
    struct o{int l,r,a,b,id;}f[100001];
    vector<oo>q[300001];
    vector<o>g[300001];
    struct tree
    {
        int w[100001];
        #define lowbit(i) (i&(-i))
        void add(int x,int v){for(int i=x;i<=n;i+=lowbit(i))w[i]+=v;}
        int get(int x){int ans=0;for(int i=x;i;i-=lowbit(i))ans+=w[i];return ans;}
    }e1,e2;
    void build(int x,int l,int r)
    {
        s[x].l=l,s[x].r=r;
        if(l==r){num=max(num,x);return ;}
        int mid=(l+r)>>1;
        build(x<<1,l,mid),build(x<<1|1,mid+1,r);
    }
    void change(int x,oo y)
    {
        q[x].push_back(y);
        if(s[x].l==s[x].r)return ;
        int mid=(s[x].l+s[x].r)>>1;
        if(y.r<=mid)change(x<<1,y);
        else change(x<<1|1,y); 
    }
    void add(int x,o y)
    {
        if(y.a<=s[x].l&&y.b>=s[x].r)
        {
            g[x].push_back(y);
            return ;
        }
        int mid=(s[x].l+s[x].r)>>1;
        if(y.a<=mid)add(x<<1,y);
        if(y.b>mid)add(x<<1|1,y);
    }
    bool cmp(o a,o b){return a.r<b.r;}
    int main()
    {
        read(n),read(m),build(1,1,n);
        for(rg int i=1,x;i<=n;i++)read(x),change(1,(oo){i,x});
        for(rg int i=1;i<=m;i++){o now;read(now.l),read(now.r),read(now.a),read(now.b),now.id=i,add(1,now);}
        for(rg int i=1;i<=num;i++)
        {
            int a=q[i].size(),b=g[i].size(),k=0;
            if(!b)continue;
            for(rg int j=1;j<=a;j++)z[j]=q[i][j-1].l;
            sort(g[i].begin(),g[i].end(),cmp);
            while(k<b&&g[i][k].r<z[1])k++;
            for(rg int j=1;j<=a;j++)
            {
                if(las[q[i][j-1].r])e2.add(las[q[i][j-1].r],-1);
                las[q[i][j-1].r]=j;
                e1.add(j,1),e2.add(j,1);
                while(k<b&&(j==a||g[i][k].r<z[j+1]))
                {
                    int t=lower_bound(z+1,z+a+1,g[i][k].l)-z;
                    ans[g[i][k].id]+=e1.get(j)-e1.get(t-1);
                    ans1[g[i][k].id]+=e2.get(j)-e2.get(t-1);
                    k++;
                }
            }
            for(rg int j=1;j<=a;j++)
            {
                if(las[q[i][j-1].r])e2.add(las[q[i][j-1].r],-1);
                e1.add(j,-1),las[q[i][j-1].r]=0;
            }
        }
        for(rg int i=1;i<=m;i++)printf("%d %d
    ",ans[i],ans1[i]);
    }
    
  • 相关阅读:
    Codeforces Round #563 (Div. 2)B;Ehab Is an Odd Person
    Codeforces Round #563 (Div. 2)C. Ehab and a Special Coloring Problem
    Codeforces Round #567 (Div. 2) A.Chunga-Changa
    Codeforces Round #569 (Div. 2) B. Nick and Array
    Codeforces Round #570 (Div. 3) B. Equalize Prices
    2019年银联极客挑战赛第一题
    js点击保存图片
    vant地区三级联动
    input 输入金额正则判断
    git 实用命令
  • 原文地址:https://www.cnblogs.com/lcxer/p/10076500.html
Copyright © 2011-2022 走看看