• BZOJ4170:极光


    浅谈离线分治算法:https://www.cnblogs.com/AKMer/p/10415556.html

    题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=4170

    出题人语文小学水平没达到系列(

    这就是一个有时间先后的二维加点二维数点问题。每个点是((i,a_i))

    先把坐标轴转化一下,让曼哈顿距离变成切比雪夫距离。((x,y)--->(x+y,x-y))

    然后询问就变成矩阵询问了。

    时间复杂度:(O(nlog^2n))

    空间复杂度:(O(n+)玄学值域大小())

    代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define low(i) ((i)&(-(i)))
    #define X x+y
    #define Y x-y
    
    const int maxn=6e4+6;
    
    char s[20];
    int n,m,cnt,ans_cnt;
    int a[maxn],ans[maxn];
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    struct Oper {
    	int opt,id,x,y,v,tim;
    
    	Oper() {}
    
    	Oper(int _opt,int _id,int _x,int _y,int _v,int _tim) {
    		opt=_opt,id=_id,x=_x,y=_y,v=_v,tim=_tim;
    	}
    }p[maxn*5];
    
    bool cmp(Oper a,Oper b) {
    	if(a.x==b.x)return a.tim<b.tim;
    	return a.x<b.x;
    }
    
    struct tree_array {
    	int c[500005];
    
    	void add(int pos,int v) {
    		pos+=240000;
    		for(int i=pos;i<=500000;i+=low(i))
    			c[i]+=v;
    	}
    
    	int query(int pos) {
    		pos+=240000;
    		int res=0;
    		for(int i=pos;i;i-=low(i))
    			res+=c[i];
    		return res;
    	}
    }T;
    
    void solve(int l,int r) {
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	solve(l,mid),solve(mid+1,r);
    	sort(p+l,p+r+1,cmp);
    	for(int i=l;i<=r;i++)
    		if(p[i].opt&&p[i].tim<=mid)T.add(p[i].y,1);
    		else if(!p[i].opt&&p[i].tim>mid)ans[p[i].id]+=p[i].v*T.query(p[i].y);
    	for(int i=l;i<=r;i++)
    		if(p[i].opt&&p[i].tim<=mid)T.add(p[i].y,-1);
    }
    
    int main() {
    	cnt=n=read(),m=read();
    	for(int x=1,y;x<=n;x++) {
    		a[x]=y=read();
    		p[x]=Oper(1,0,X,Y,0,x);
    	}
    	for(int i=1;i<=m;i++) {
    		scanf("%s",s+1);
    		if(s[1]=='Q') {
    			int x=read(),y=a[x],limit=read();++ans_cnt;
    			++cnt,p[cnt]=Oper(0,ans_cnt,X+limit,Y+limit,1,cnt);
    			++cnt,p[cnt]=Oper(0,ans_cnt,X+limit,Y-limit-1,-1,cnt);
    			++cnt,p[cnt]=Oper(0,ans_cnt,X-limit-1,Y+limit,-1,cnt);
    			++cnt,p[cnt]=Oper(0,ans_cnt,X-limit-1,Y-limit-1,1,cnt);
    		}
    		else {
    			int x=read(),y=read();a[x]=y;
    			++cnt,p[cnt]=Oper(1,0,X,Y,0,cnt);
    		}
    	}
    	solve(1,cnt);
    	for(int i=1;i<=ans_cnt;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    脚本——1-100的和
    脚本——删除文件为0大小的文件
    脚本——ping网址
    脚本——大于5k的文件有
    脚本——九九乘法表
    第十天:小数与随机数
    第九天:单元测试
    第八天:错误异常处理
    第七天(1):包与模块管理
    第七天(2):面向对象编程
  • 原文地址:https://www.cnblogs.com/AKMer/p/10418774.html
Copyright © 2020-2023  润新知