• 「SNOI2017」一个简单的询问


    「SNOI2017」一个简单的询问

    简单的解法

    显然可以差分一下。

    [get(l,r,x) imes get(l1,r1,x)=get(1,r,x) imes get(1,r1,x)-get(1,l-1,x) imes get(1,r1,x)-get(1,r,x) imes get(1,l1-1,x)+get(1,l-1,x) imes get(1,l1-1,x) ]

    因为都是1为起始,那么记两个cnt数组,表示前缀,然后可以分成四个区间,莫队。

    #include <bits/stdc++.h>
    #define rep(q, a, b) for (int q = a, q##_end_ = b; q <= q##_end_; ++q)
    #define dep(q, a, b) for (int q = a, q##_end_ = b; q >= q##_end_; --q)
    #define mem(a, b) memset(a, b, sizeof a)
    #define debug(a) cerr << #a << ' ' << a << "___" << endl
    using namespace std;
    bool cur1;
    char buf[10000000], *p1 = buf, *p2 = buf;
    #define Getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 10000000, stdin), p1 == p2) ? EOF : *p1++
    void in(int &r) {
        static char c;
        r = 0;
        while (c = Getchar(), c < 48)
            ;
        do
            r = (r << 1) + (r << 3) + (c ^ 48);
        while (c = Getchar(), c > 47);
    }
    const int mn = 50005;
    int K, n, val[mn];
    long long ans[mn];
    struct node {
        int l, r, id, ty;
        bool operator<(const node &A) const {
            return l / K == A.l / K ? (l / K & 1 ? r > A.r : r < A.r) : l / K < A.l / K;
        }
    } an[mn * 4];
    int cnt[mn], cnt1[mn];
    long long mid_ans;
    bool cur2;
    int main() {
        //	cerr<<(&cur2-&cur1)/1024.0/1024<<endl;
        in(n);
        K = sqrt(n) + 1;
        rep(q, 1, n) in(val[q]);
        int Q;
        in(Q);
        int l, r, l1, r1;
        int ct = 0;
        rep(q, 1, Q) {
            in(l), in(r), in(l1), in(r1);
            an[++ct] = { r, r1, q, 1 };
            if (l > 1) {
                an[++ct] = { l - 1, r1, q, -1 };
                if (l1 > 1)
                    an[++ct] = { l1 - 1, l - 1, q, 1 };
            }
            if (l1 > 1)
                an[++ct] = { l1 - 1, r, q, -1 };
        }
        sort(an + 1, an + ct + 1);
        l = 0, r = 0;
        rep(q, 1, ct) {
            while (l > an[q].l) mid_ans -= cnt1[val[l]], --cnt[val[l--]];
            while (r < an[q].r) mid_ans += cnt[val[++r]], ++cnt1[val[r]];
            while (l < an[q].l) mid_ans += cnt1[val[++l]], ++cnt[val[l]];
            while (r > an[q].r) mid_ans -= cnt[val[r]], --cnt1[val[r--]];
            ans[an[q].id] += mid_ans * an[q].ty;
        }
        rep(q, 1, Q) printf("%lld
    ", ans[q]);
        return 0;
    }
    

    麻烦的解法

    对于两个区间([l,r],[l1,r1](l leq l1)),分三类容斥:

    1. 没有交
    2. ([l1,r1])([l,r])包含
    3. 两个区间相交且没有包含关系

    对于1

    ([l,r])值为K数有x,([r+1,l1-1])值为K数有y,([l1,r1])值为K数有z。

    [xz= {(x+y+z)^2-(x+y)^2-(y+z)^2+y^2over 2} ]

    因此可以拆成4个区间计算。

    对于2

    ([l,l1-1])值为K数有x,([l1,r1])值为K数有y,([r1+1,r])值为K数有z。

    [y(x+y+z)={(x+y)^2+(y+z)^2-x^2-z^2 over 2} ]

    因此可以拆成4个区间计算。

    对于3

    ([l,l1-1])值为K数有x,([l1,r])值为K数有y,([r+1,r1])值为K数有z。

    [(x+y)(y+z)= {(x+y+z)^2-x^2-z^2+y^2over 2} ]

    因此可以拆成4个区间计算。

    综上

    一遍莫队即可,计算区间中相同数个数的平方的和。

    #include<bits/stdc++.h>
    #define rep(q,a,b) for(int q=a,q##_end_=b;q<=q##_end_;++q)
    #define dep(q,a,b) for(int q=a,q##_end_=b;q>=q##_end_;--q)
    #define mem(a,b) memset(a,b,sizeof a )
    #define debug(a) cerr<<#a<<' '<<a<<"___"<<endl
    using namespace std;
    bool cur1;
    char buf[10000000],*p1=buf,*p2=buf;
    #define Getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,10000000,stdin),p1==p2)?EOF:*p1++
    void in(int &r) {
        static char c;
        r=0;
        while(c=Getchar(),c<48);
        do r=(r<<1)+(r<<3)+(c^48);
        while(c=Getchar(),c>47);
    }
    const int mn=50005;
    int K,n,val[mn];
    long long ans[mn];
    struct node{
    	int l,r,id,ty;
    	bool operator <(const node &A)const{
    		return l/K==A.l/K?(l/K&1?r>A.r:r<A.r):l/K<A.l/K;
    	}
    }an[mn*4];
    int cnt[mn];
    long long mid_ans;
    bool cur2;
    int main(){
    //	cerr<<(&cur2-&cur1)/1024.0/1024<<endl;
    	in(n);
    	K=sqrt(n)+1;
    	rep(q,1,n)in(val[q]);
    	int Q;
    	in(Q);
    	int l,r,l1,r1;
    	int ct=0;
    	rep(q,1,Q){
    		in(l),in(r),in(l1),in(r1);
    		if(l>l1)swap(l,l1),swap(r,r1);
    		if(r<l1){
    			an[++ct]={l,r1,q,1};
    			an[++ct]={l,l1-1,q,-1};
    			an[++ct]={r+1,r1,q,-1};
    			if(l1-1>=r+1)an[++ct]={r+1,l1-1,q,1};
    		}else if(r1<=r){
    			an[++ct]={l,r1,q,1};
    			an[++ct]={l1,r,q,1};
    			if(l<=l1-1)an[++ct]={l,l1-1,q,-1};
    			if(r1+1<=r)an[++ct]={r1+1,r,q,-1};
    		}else{
    			an[++ct]={l,r1,q,1};
    			an[++ct]={l1,r,q,1};
    			if(l<=l1-1)an[++ct]={l,l1-1,q,-1};
    			if(r+1<=r1)an[++ct]={r+1,r1,q,-1};
    		}
    	}
    	sort(an+1,an+ct+1);
    	mid_ans=1,cnt[val[1]]=1;
    	l=1,r=1;
    	rep(q,1,ct){
    		while(l>an[q].l)--l,mid_ans+=(cnt[val[l]]++)<<1|1;
    		while(r<an[q].r)++r,mid_ans+=(cnt[val[r]]++)<<1|1;
    		while(l<an[q].l)mid_ans-=(--cnt[val[l]])<<1|1,++l;
    		while(r>an[q].r)mid_ans-=(--cnt[val[r]])<<1|1,--r;
    		ans[an[q].id]+=mid_ans*an[q].ty;
    	}
    	rep(q,1,Q)printf("%lld
    ",ans[q]>>1);
        return 0;
    }
    
  • 相关阅读:
    ajax如何调用本页数据源不用一般处理程序
    管理员IP匹配方法
    Silverlight DataGrid赋数据源自动生成列表
    Winform WebBrowser加上进度条
    asp.net的几个帮助类
    asp.net App.config配置文件帮助类
    查找集合中某个元素的位置和某个元素的集合
    sqlServer通用分页
    定时执行某个方法
    关于IE6.7.8.FF兼容的问题
  • 原文地址:https://www.cnblogs.com/klauralee/p/10948943.html
Copyright © 2020-2023  润新知