zoukankan      html  css  js  c++  java
  • CF 848C

    听说,一个好的oier是题目喂出来的。

    题目

    给定长度为n的数组, 定义数字X在[l,r]内的值为数字X在[l,r]内最后一次出现位置的下标减去第一次出现位置的下标

    给定m次询问, 每次询问有三个整数a,b,c询问规则如下:

    当a=1时, 将数组内第b个元素更改为c

    当a=2时, 求区间[b,c]所有数字的值的和

    解题思路

    不难想到对于每个点,记录上一个权值和他相同的点的下标(不妨称之为前驱),设他的权值为这两个下标之差。

    于是可以发现 [l,r] 的权值可以基本表示为[l,r]内所有点的权值和。

    但我们很快发现,我们多加了一些。

    而后修正为[l,r]内所有前驱也在[l,r]内的点的权值和。

    然后看着就很像查询二维平面上一个矩形的和了。

    CDQ分治即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int sz=7e5+527;
    struct hh{
    	int x,y,t,val;
    }tmp[sz],q[sz];
    int n,m;
    int tot,cnt;
    int type,x,y;
    ll a[sz],f[sz];
    ll ans[sz];
    set<int>S[sz];
    set<int>::iterator it;
    int head[sz],lst[sz];
    void update(int x,int sum){
    	for(;x<=n+1;x+=(x&(-x))) f[x]+=sum;
    }
    ll query(int x){
    	ll ret=0;
    	for(;x;x-=x&(-x)) ret+=f[x];
    	return ret;
    }
    void cdq(int l,int r){
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	cdq(l,mid),cdq(mid+1,r);
    	int i=l,j=mid+1,k=l-1;
    	while(i<=mid||j<=r){
    		if(j>r || i<=mid && (q[i].x<q[j].x || q[i].x==q[j].x &&q[i].t<q[j].t)){
    			if(!q[i].t) update(q[i].y,q[i].val);
    			tmp[++k]=q[i];
    			i++;
    		}
    		else{
    			if(q[j].t){
    				int num=abs(q[j].val);
    				if(q[j].val>0) ans[num]+=query(q[j].y);
    				else ans[num]-=query(q[j].y);
    			}
    			tmp[++k]=q[j];
    			j++;
    		}
    	}
    	for(int i=l;i<=mid;i++) if(!q[i].t) update(q[i].y,-q[i].val);
    	for(int i=l;i<=r;i++) q[i]=tmp[i];
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		S[a[i]].insert(i);
    		lst[i]=head[a[i]],head[a[i]]=i;
    		q[++tot]=(hh){i,lst[i],0,i-lst[i]};
    	}
    	for (int i=1; i<=m; ++i){
            scanf("%d%d%d",&type,&x,&y);
            if (type==1){
                int p1=0,n1=0;//前驱 后继 
                it=S[a[x]].find(x);
                if (it!=S[a[x]].begin()) --it, p1=*it, ++it;
                if ((++it)!=S[a[x]].end()) n1=*it; --it;
                S[a[x]].erase(*it); q[++tot]=(hh){x,lst[x],0,lst[x]-x};
                if(n1){
                    q[++tot]=(hh){n1,lst[n1],0,lst[n1]-n1};
                    lst[n1]=p1;
                    q[++tot]=(hh){n1,lst[n1],0,n1-lst[n1]};
                }
                int p2=0,n2=0;
                a[x]=y; S[a[x]].insert(x);
                it=S[a[x]].find(x);
                if (it!=S[a[x]].begin()) --it, p2=*it, ++it;
                if ((++it)!=S[a[x]].end()) n2=*it; --it;
                lst[x]=p2; q[++tot]=(hh){x,lst[x],0,x-lst[x]};
                if (n2){
                    q[++tot]=(hh){n2,lst[n2],0,lst[n2]-n2};
                    lst[n2]=x;
                    q[++tot]=(hh){n2,lst[n2],0,n2-lst[n2]};
                }
            }
            else{
                ++cnt;
                q[++tot]=(hh){x-1,x-1,1,cnt};
                q[++tot]=(hh){y,y,1,cnt};
                q[++tot]=(hh){x-1,y,1,-cnt};
                q[++tot]=(hh){y,x-1,1,-cnt};
            }
        }
        for (int i=1; i<=tot; ++i) q[i].x++, q[i].y++;
        cdq(1,tot);
        for(int i=1;i<=cnt;i++) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    request.getParameter() 、 request.getInputStream()和request.getReader() 使用体会
    HTTP之Content-Length
    关于spring3中No Session found for current thread!and Transaction的配置和管理(转)
    Java数据类型和MySql数据类型对应一览
    Spring MVC 解读——View,ViewResolver(转)
    LeetCode 441. Arranging Coins
    LeetCode 415. Add Strings
    LeetCode 400. Nth Digit
    LeetCode 367. Valid Perfect Square
    LeetCode 326. Power of Three
  • 原文地址:https://www.cnblogs.com/river-flows-in-you/p/11291811.html
Copyright © 2011-2022 走看看