• [洛谷P2184]贪婪大陆


    题目大意:有n个点,每次在l~r之间所有点各加上同一种地雷,或询问某一区间内地雷种数。

    解题思路:首先注意是“加上”而不是“覆盖”。

    然后我们用两棵线段树(树状数组),一棵维护某一区间内左端点个数,另一棵维护右端点个数。

    由于每次只加上一个端点,故为单点修改。

    那么如何查询呢?

    如果1~r内有a个左端点,则说明最多有a种地雷,如果1~l-1内有b个右端点,则说明a种地雷中,有b种的右端点没有达到l(否则一定在l-1之后)。

    那么查询出a和b,然后输出a-b即可。

    很明显是区间修改。

    时间复杂度$O(mlog_2 n)$。

    C++ Code:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #define N 100005
    int n,m,R,ans,d1[N<<2],d2[N<<2];
    inline int readint(){
    	char c=getchar();
    	for(;!isdigit(c);c=getchar());
    	int d=0;
    	for(;isdigit(c);c=getchar())
    	d=(d<<3)+(d<<1)+(c^'0');
    	return d;
    }
    void add1(int l,int r,int o){
    	++d1[o];
    	if(l!=r){
    		int mid=l+r>>1;
    		if(R<=mid)add1(l,mid,o<<1);
    		if(mid<R)add1(mid+1,r,o<<1|1);
    	}
    }
    void add2(int l,int r,int o){
    	++d2[o];
    	if(l!=r){
    		int mid=l+r>>1;
    		if(R<=mid)add2(l,mid,o<<1);
    		if(mid<R)add2(mid+1,r,o<<1|1);
    	}
    }
    void query1(int l,int r,int o){
    	if(r<=R)ans+=d1[o];else{
    		int mid=l+r>>1;
    		query1(l,mid,o<<1);
    		if(mid<R)query1(mid+1,r,o<<1|1);
    	}
    }
    void query2(int l,int r,int o){
    	if(r<=R)ans+=d2[o];else{
    		int mid=l+r>>1;
    		query2(l,mid,o<<1);
    		if(mid<R)query2(mid+1,r,o<<1|1);
    	}
    }
    int main(){
    	n=readint(),m=readint();
    	memset(d1,0,sizeof d1);
    	memset(d2,0,sizeof d2);
    	while(m--){
    		int opt=readint(),l=readint(),r=readint();
    		if(opt==1){
    			R=l;
    			add1(1,n,1);
    			R=r;
    			add2(1,n,1);
    		}else{
    			int Ans=0;
    			ans=0;
    			R=r;
    			query1(1,n,1);
    			Ans+=ans;
    			ans=0;
    			R=l-1;
    			if(R)
    			query2(1,n,1);
    			Ans-=ans;
    			printf("%d
    ",Ans);
    		}
    	}
    	return 0;
    }
  • 相关阅读:
    C#小型资源管理器
    C#换肤LrisSkin
    面向对象的24种设计模式
    七大设计原则
    非泛型集合和泛型集合
    C#经理评价系统
    深入C#.NET框架
    C#窗口航空总结
    java基础数据结构和语法
    HTML
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8082331.html
Copyright © 2020-2023  润新知