zoukankan      html  css  js  c++  java
  • [雅礼集训 2017 Day1]市场(线段树)

    (Description)

    从前有一个贸易市场,在一位执政官到来之前都是非常繁荣的,自从他来了之后,发布了一系列奇怪的政令,导致贸易市场的衰落。 有(n)个商贩,从(0sim n-1)编号,每个商贩的商品有一个价格(a_{i}),有两种政令;同时,有一个外乡的旅客想要了解贸易市场的信息,有两种询问方式:

    在这里插入图片描述


    (Input)

    第一行为两个空格隔开的整数(n,q)分别表示商贩个数和政令(+)询问个数。
    第二行包含(n)个由空格隔开的整数(a_{0}sim a_{n-1})
    接下来(q)行,每行表示一个操作,第一个数表示操作编号(1sim 4),接下来的输入和问题描述一致。


    (Output)

    对于每个(3、4)操作,输出询问答案。


    (Sample Input)

    10 10
    -5 -4 -3 -2 -1 0 1 2 3 4
    1 0 4 1
    1 5 9 1
    2 0 9 3
    3 0 9
    4 0 9
    3 0 1
    4 2 3
    3 4 5
    4 6 7
    3 8 9


    (Sample Output)

    -2
    -2
    -2
    -2
    0
    1
    1


    (HINT)

    对于(30\%)的数据,(n,qle10^3)
    对于(60\%)的数据,保证数据随机;
    对于(100\%)的数据,(n,q≤1×10^5,|c|≤1×10^4,d∈[2,1×10^9]), 时限(2s)


    思路

    第一眼看上去:这道题是一道线段树板子题(别喷

    第二眼看上去:嗯?这个操作(2)有点意思

    第三眼看上去:(woc) ,这个操作(2)使得这个线段树板子题难了不止一点

    隔壁大佬 (lcw):这哪里难了,不就是个区间减法吗

    我蒟蒻:啊?这明明是区间除法,怎么就成区间减法了

    大佬 (lcw) :除法难道不可以用减法实现吗

    我蒟蒻:但是按照除法用减法实现的思想来所的话,是将每个区间内的数减去一个数得到除于(d)之后的答案了,但是区间内的数要减去的数各不相同,怎么处理?

    大佬 (lcw) :这你就不懂了吧,我们可以找到一个区间,使得区间里面的每一个数减去同一个数都可以得到其相应的除于(d)得到的数

    我蒟蒻:啊,怎么求啊

    大佬 (lcw) : 这题目中不是要求区间最小值(mn)吗,我们就顺其自然,再维护一个区间最大值(mx),如果(mx-frac{mx}{d}==mn-frac{mn}{d}),那么不就是说明,这个区间内的所有数减去这个数本身除于(d)的数都相等,是不是说明我们可以得到一个值(t),使得这个区间内的所有(a_{i}-t=frac{a_{i}}{d}),这样我们就可以实现区间减法了

    我蒟蒻:区间减法我是懂了,但是怎么证复杂度呢,这样不会奇怪的变成(O(n^2))的复杂度???

    大佬 (lcw) :✓,这个问题你问的算是有水平,接下来就让哥给你证证

    (lcw) 大佬的表演时间:

    我们就先考虑普遍情况,如果只有除法操作,那么易得,很快经过(log_{a_{i}})次除法,就会归(1)了,所以算它复杂度为(O(log_{a_{i}}))

    但是如果加入了加法操作,每次加法操作最多会使得一个本来可以进行区间减法的区间最多分成(log_{n})块,所以最终的复杂度是(O(qlog_{v}log_{n}))


    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ls(x) x<<1
    #define rs(x) x<<1|1
    typedef long long ll;
    const int N=1e5+10;
    int n,q;
    ll a[N];
    struct tree
    {
    	ll ch[2],val,mx,mn,siz;
    	ll tag1;
    }t[N<<4];
    void up(int k)
    {
    	t[k].val=t[ls(k)].val+t[rs(k)].val;
    	t[k].mn=min(t[ls(k)].mn,t[rs(k)].mn);
    	t[k].mx=max(t[ls(k)].mx,t[rs(k)].mx);
    }
    void build(int k,int l,int r)
    {
    	t[k].siz=(r-l+1);
    	if(l==r)
    	{
    		t[k].val=a[l];
    		t[k].mn=a[l];
    		t[k].mx=a[l];
    		return ;
    	}
    	int mid=(l+r)>>1;
    	build(ls(k),l,mid);
    	build(rs(k),mid+1,r);
    	up(k);
    }
    ll divide(ll x,ll y)
    {
    	return floor((double)x/y);
    }
    void modify(int k,ll v)
    {
    	t[k].val+=t[k].siz*v;
    	t[k].mx+=v;
    	t[k].mn+=v;
    	t[k].tag1+=v;
    }
    void pushdown(int k)
    {
    	if(t[k].tag1)
    	{
    		modify(ls(k),t[k].tag1);
    		modify(rs(k),t[k].tag1);
    		t[k].tag1=0;
    	}
    }
    void add(int k,int l,int r,int x,int y,ll z)
    {
    	if(x<=l&&r<=y)
    	{
    		modify(k,z);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	pushdown(k);
    	if(x<=mid)add(ls(k),l,mid,x,y,z);
    	if(y>mid)add(rs(k),mid+1,r,x,y,z);
    	up(k);
    }
    void div(int k,int l,int r,int x,int y,ll z)
    {
    	if(x<=l&&r<=y)
    	{
    		ll tmp1=divide(t[k].mx,z),tmp2=divide(t[k].mn,z);
    		if(t[k].mx-tmp1==t[k].mn-tmp2)
    		{
    			modify(k,tmp1-t[k].mx);
    			return ;
    		}
    	}
    	int mid=(l+r)>>1;
    	pushdown(k);
    	if(x<=mid)div(ls(k),l,mid,x,y,z);
    	if(y>mid)div(rs(k),mid+1,r,x,y,z);
    	up(k);
    }
    ll query_min(int k,int l,int r,int x,int y)
    {
    	if(x<=l&&r<=y)return t[k].mn;
    	int mid=(l+r)>>1;
    	ll ans=0x7ffffffffffffff;
    	pushdown(k);
    	if(x<=mid)ans=min(ans,query_min(ls(k),l,mid,x,y));
    	if(y>mid)ans=min(ans,query_min(rs(k),mid+1,r,x,y));
    	return ans;
    }
    ll query_sum(int k,int l,int r,int x,int y)
    {
    	if(x<=l&&r<=y)return t[k].val;
    	int mid=(l+r)>>1;
    	ll ans=0ll;
    	pushdown(k);
    	if(x<=mid)ans+=query_sum(ls(k),l,mid,x,y);
    	if(y>mid)ans+=query_sum(rs(k),mid+1,r,x,y);
    	return ans;
    }
    void debug(int k,int l,int r)
    {
    	printf("%d %d %d %d %d %d
    ",k,l,r,t[k].siz,t[k].val,t[k].mn);
    	if(l==r)return ;
    	int mid=(l+r)>>1;
    	debug(ls(k),l,mid);debug(rs(k),mid+1,r);
    }
    int main()
    {
    	scanf("%d %d",&n,&q);
    	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    	build(1,1,n);
    /*	cout<<"debug begin!!!"<<endl<<endl;
    	debug(1,1,n);
    	cout<<"debug end!!!"<<endl<<endl;
    //	system("pause");*/
    	int op,x,y;
    	ll z;
    	while(q--)
    	{
    		scanf("%d %d %d",&op,&x,&y);
    		x++,y++;
    		if(op==1)scanf("%lld",&z),add(1,1,n,x,y,z);
    		if(op==2)scanf("%lld",&z),div(1,1,n,x,y,z);
    		if(op==3)printf("%lld
    ",query_min(1,1,n,x,y));
    		if(op==4)printf("%lld
    ",query_sum(1,1,n,x,y));
    		/*cout<<"debug begin!!!"<<endl<<endl;
    		debug(1,1,n);
    		cout<<"debug end!!!"<<endl<<endl;
    //		system("pause");*/
    	}
    	return 0;
    }
    /*
    10 10
    -5 -4 -3 -2 -1 0 1 2 3 4
    1 0 4 1
    1 5 9 1
    2 0 9 3
    3 0 9
    4 0 9
    3 0 1
    4 2 3
    3 4 5
    4 6 7
    3 8 9
    */
    /*
    -4 -3 -2 -1 0 0 1 2 3 4
    -4 -3 -2 -1 0 1 2 3 4 5
    -2 -1 -1 -1 0 0 0 1 1 1 
    */
    
  • 相关阅读:
    windows,linux,esxi系统判断当前主机是物理机还是虚拟机?查询主机序列号命令 风行天下
    zabbix监控网络的出入口流量 风行天下
    python 编写远程连接服务器脚本 风行天下
    zabbix 监控windows端cpu使用率百分比 风行天下
    linux计划任务crontab的使用 风行天下
    cd
    rm
    cp
    Windows XP和Windows 7双系统安装和启动菜单修复
    MapInfo、ArcGIS 狙击战 1
  • 原文地址:https://www.cnblogs.com/ShuraEye/p/11779890.html
Copyright © 2011-2022 走看看